Hello, i'm using SwiftQueue to createa upload/download queue in my app.
When i try to run the queue return allways the same image for all objects in que
Can you help me?
I have arround 500 images to upload but queue only run the same job for te 500 images.
What i'm doing wrong, im using the last version of pod.
`import Foundation
import SwiftQueue
import Crashlytics
import Alamofire
class MIImagesInQueueDownload: NSObject, NSCoding {
var url: String?
init(url: String?) {
self.url = url
}
func encode(with aCoder: NSCoder) {
aCoder.encode(url, forKey: "url")
}
required init(coder aDecoder: NSCoder) {
if let url = aDecoder.decodeObject(forKey: "url") as? String {
self.url = url
}
}
static func ==(lhs: MIImagesInQueueDownload, rhs: MIImagesInQueueDownload) -> Bool {
return lhs.url ?? "" == rhs.url ?? ""
}
}
class MIImagesInQueueUpload: NSObject, NSCoding {
var filePath: String = ""
var fileName: String = ""
var assignmentUUID: String = ""
var url:String = ""
init(filePath: String, fileName: String, assignmentUUID: String, url:String) {
self.fileName = fileName
self.filePath = filePath
self.assignmentUUID = assignmentUUID
self.url = url
}
func encode(with aCoder: NSCoder) {
aCoder.encode(filePath, forKey: "filePath")
aCoder.encode(fileName, forKey: "fileName")
aCoder.encode(assignmentUUID, forKey: "assignmentUUID")
aCoder.encode(url, forKey: "url")
}
required init(coder aDecoder: NSCoder) {
if let filename = aDecoder.decodeObject(forKey: "fileName") as? String {
self.fileName = filename
}
if let filePath = aDecoder.decodeObject(forKey: "filePath") as? String {
self.filePath = filePath
}
if let uuid = aDecoder.decodeObject(forKey: "assignmentUUID") as? String {
self.assignmentUUID = uuid
}
if let url = aDecoder.decodeObject(forKey: "url") as? String {
self.url = url
}
}
static func ==(lhs: MIImagesInQueueUpload, rhs: MIImagesInQueueUpload) -> Bool {
return lhs.fileName == rhs.fileName && lhs.assignmentUUID == rhs.assignmentUUID && lhs.filePath == rhs.filePath && lhs.url == rhs.url
}
}
public struct ImageError: Error {
let msg: String
}
public struct UploadError: Error {
let msg: String
}
extension ImageError: LocalizedError {
public var errorDescription: String? {
return NSLocalizedString(msg, comment: "")
}
}
extension UploadError: LocalizedError {
public var errorDescription: String? {
return NSLocalizedString(msg, comment: "")
}
}
class downloadOperation: Job {
let image: MIImagesInQueueDownload
static let type = "downloadImage"
required init(image: MIImagesInQueueDownload) {
self.image = image
}
func onRun(callback: JobResult) {
self.downloadImage(with: self.image) { (error) in
if let error = error {
callback.done(.fail(error))
} else {
callback.done(.success)
}
}
}
func onRetry(error: Error) -> RetryConstraint {
if error is UploadError {
return RetryConstraint.retry(delay: 3600)
} else {
return RetryConstraint.cancel
}
}
func onRemove(result: JobCompletion) {
// This job will never run anymore
switch result {
case .success:
// Job success
break
case .fail(let error):
Logger.shared.log(message: error.localizedDescription, vc: "ImageDownload JOB")
break
}
}
private func downloadImage(with image:MIImagesInQueueDownload, onComplete:@escaping onCompleteupload) {
guard let urlImage = image.url?.encodeURL() else { return }
MIImageQueue.shared.imageDownloader.downloadImage(with: urlImage, options: [], progressBlock: nil) { (image, error, url, data) in
Logger.shared.log(message: error?.localizedDescription ?? "", vc: "imageDowload")
guard let image = image else {
onComplete(ImageError(msg: "missing file at server"))
return
}
guard let url = url else {
onComplete(ImageError(msg: "missing file at server"))
return
}
MIHelper.shared.storeImage(image: image, fileURL: url.absoluteString, fileName: url.lastPathComponent, execute: { (imageDevice) in
onComplete(nil)
})
}
}
}
class uploadOperation: Job {
let image: MIImagesInQueueUpload
lazy var uploadQueue: DispatchQueue = {
var queue = DispatchQueue(label: "com.uscope.photoId.ImagesUpload",
qos: DispatchQoS.background,
attributes: .concurrent,
autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit,
target: DispatchQueue.global(qos: .background))
return queue
}()
static let type = "uploadImage"
required init(image: MIImagesInQueueUpload) {
self.image = image
print(image.filePath)
}
func onRun(callback: JobResult) {
print(image.fileName)
self.uploadImage(with: self.image) { (error) in
if let error = error {
callback.done(.fail(error))
} else {
callback.done(.success)
}
}
}
func onRetry(error: Error) -> RetryConstraint {
if error is UploadError || error is ImageError {
return RetryConstraint.retry(delay: 3600)
} else {
return RetryConstraint.cancel
}
}
func onRemove(result: JobCompletion) {
// This job will never run anymore
switch result {
case .success:
// Job success
break
case .fail(let error):
Logger.shared.log(message: error.localizedDescription, vc: "ImageUpload JOB")
break
}
}
fileprivate func uploadImage(with imageQueue:MIImagesInQueueUpload, onComplete:@escaping onCompleteupload){
let object = imageQueue
if let filePathURL = URL(string: imageQueue.filePath), let profileIdToSet = imageQueue.url.getProfileID() {
let filePath = filePathURL.imagesFolderPath()
if filePath.extists() {
let parameters:Parameters = ["filename": object.fileName, "sourceFileUri": filePath.absoluteString, "assignmentId": object.assignmentUUID, "profileId": profileIdToSet]
let parametersLog:[String:String] = ["filename": object.fileName, "assignmentId": object.assignmentUUID, "profileId": profileIdToSet]
print(parameters)
Answers.logCustomEvent(withName: "image upload", customAttributes: parametersLog)
MIConnnection.shared.alamofireManager.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(filePath, withName: "bill", fileName: object.fileName.isEmpty ? filePath.getImageName() : object.fileName, mimeType: "image/jpeg")
}, with: APINetworkRouter.upload(parameters: parameters), encodingCompletion: { [weak self] (result) in
guard let strongSelf = self else { return }
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
Logger.shared.log(message: "Upload progress \(progress.fractionCompleted)", vc: String(describing: self))
})
upload.customValidation().responseJSON(queue: strongSelf.uploadQueue, completionHandler: { (response) in
switch response.result {
case .success(let responseJSON):
guard let responseObject = responseJSON as? DefaultDict else { return }
guard let success = responseObject["success"]?.boolValue else { return }
guard let message = responseObject["message"] as? String else { return }
if success {
Answers.logCustomEvent(withName: "image upload success", customAttributes: ["success" : success, "message": message])
let objectNotification = ["url": imageQueue.url.getImageNameWhitoutURL(), "assignmnentId" : object.assignmentUUID]
NotificationCenter.default.post(name: Notifications.didChangeUpload, object: nil, userInfo:objectNotification)
DispatchQueue.main.async {
onComplete(nil)
}
} else {
DispatchQueue.main.async {
onComplete(UploadError(msg: message))
}
Answers.logCustomEvent(withName: "image upload fail", customAttributes: ["success" : success, "message": message])
return
}
case .failure(let error):
if isDebug {
error.manageAlamofireError()
}
DispatchQueue.main.async {
onComplete(UploadError(msg: error.localizedDescription))
}
return
}
})
case .failure(let error):
if isDebug {
error.manageAlamofireError()
}
onComplete(error)
return
}
})
} else {
DispatchQueue.main.async {
onComplete(ImageError(msg: "missing file at disk"))
}
Answers.logCustomEvent(withName: "image upload fail", customAttributes: ["error" : "missing file at disk"])
}
}
}
}
class UploaderDownloaderManager {
static let shared:UploaderDownloaderManager = UploaderDownloaderManager()
let queueManager = SwiftQueueManagerBuilder(creator: mainJobCreator()).set(logger: ConsoleLogger()).build()
func uploadImage(with imageQueue:MIImagesInQueueUpload) {
if let user = MIFirebaseDatabaseManager.shared.userApp {
JobBuilder(type: uploadOperation.type)
// Prevent adding the same job multiple times
.singleInstance(forId: imageQueue.url)
// Different group name will run in parallel
// But one by one for a group
.group(name: "uploadPicture")
// Sending tweet will require internet. At least cellular.
// Will also be executed if connected to wifi.
.internet(atLeast: user.cellarSync ? .any : .wifi)
// Content of your tweet. Can be a class, struct or anything
.with(params: ["fileURI" : imageQueue.url, "filePath" : imageQueue.filePath, "fileName" : imageQueue.fileName, "assignmentId" : imageQueue.assignmentUUID, "profileId": user.userID])
// unlimited retry by default
.retry(limit: .limited(10))
// set persist by default
.persist(required: true)
// set periodic by default
// .periodic()
// Cancel the job if it's not completed after one week
.deadline(date: Date(timeIntervalSinceNow: 604_800))
// Insert to queue
.schedule(manager: self.queueManager)
}
}
func downloadImage(with imageQueue:MIImagesInQueueDownload) {
if let user = MIFirebaseDatabaseManager.shared.userApp {
JobBuilder(type: downloadOperation.type)
// Prevent adding the same job multiple times
.singleInstance(forId: imageQueue.url ?? "")
// Different group name will run in parallel
// But one by one for a group
.group(name: "downloadPicture")
// Sending tweet will require internet. At least cellular.
// Will also be executed if connected to wifi.
.internet(atLeast: user.cellarSync ? .any : .wifi)
// Content of your tweet. Can be a class, struct or anything
.with(params: ["fileURI" : imageQueue.url ?? ""])
// unlimited retry by default
.retry(limit: .limited(5))
// set persist by default
.persist(required: true)
// set periodic by default
.periodic()
// Cancel the job if it's not completed after 24 hours
.deadline(date: Date(timeIntervalSinceNow: 86_400))
// Insert to queue
.schedule(manager: self.queueManager)
}
}
func downloadFromURL(with url:URL) {
if let user = MIFirebaseDatabaseManager.shared.userApp {
JobBuilder(type: downloadOperation.type)
// Prevent adding the same job multiple times
.singleInstance(forId: url.absoluteString)
// Different group name will run in parallel
// But one by one for a group
.group(name: "downloadPicture")
// Sending tweet will require internet. At least cellular.
// Will also be executed if connected to wifi.
.internet(atLeast: user.cellarSync ? .any : .wifi)
// Content of your tweet. Can be a class, struct or anything
.with(params: ["fileURI" : url.absoluteString])
// unlimited retry by default
.retry(limit: .limited(5))
// set persist by default
.persist(required: true)
// set periodic by default
.periodic()
// Cancel the job if it's not completed after 24 hours
.deadline(date: Date(timeIntervalSinceNow: 86_400))
// Insert to queue
.schedule(manager: self.queueManager)
}
}
}
class mainJobCreator: JobCreator {
func create(type: String, params: [String : Any]?) -> Job {
// check for job and params type
if type == downloadOperation.type {
return downloadOperation(image: MIImagesInQueueDownload(url: params?["fileURI"] as? String ?? ""))
} else if type == uploadOperation.type {
return uploadOperation(image: MIImagesInQueueUpload(filePath: params?["filePath"] as? String ?? "", fileName: params?["fileName"] as? String ?? "", assignmentUUID: params?["assignmentId"] as? String ?? "", url: params?["fileURI"] as? String ?? ""))
} else {
fatalError("No Job !")
}
}
}
`