Swift后台同步pipe理器

我想创build一个Upload Manager Singleton,每10分钟上传一个多部分数据。 上传本身是清晰的,但我怎么能做一个类,在这个时间间隔在后台上传数据?

只需指定:

我想上传的数据是一个有一个对象数组的模型。 每个对象都有一个标志,当这个标志被设置时,对象已经准备好上传了。 那整个“同步function”应该被调用一次,每10分钟重复一次,不pipe在哪个ViewController上。 有谁知道我怎么能做到这一点?

该代码使用一些外部框架。 它基于recursion。

  1. Alamofire //用于联网

*以上的框架并不重要。 我只是用它来加快开发进程。

同步pipe理器

import Foundation import Alamofire let SyncMangerIdentifier = "com.example.background.syncmanger" class SyncManager: Alamofire.Manager{ static let instance = SyncManager() private var pendingTasks = [SyncTask]() // SyncTask is a class with 3 variables [image,audio,[tags]] that are being uploading to server private var request: Request? private var isSyncing = false private init(){ let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(SyncMangerIdentifier) configuration.allowsCellularAccess = Config.cellularAccess super.init(configuration: configuration) } // CALL THIS FUNCTION TO START THE SYNC // variable isSyncing guards multiple execution of syncManager func start(){ guard !isSyncing else { // WE ARE ALREADY SYNCING return } // CALL TO PREPARE FUNCTION TO EVALUATE WHETHER WE CAN SYNC OR NOT prepare() } /* initialize the syncItem variable with the first entry from SyncTask if we are stopping return if syncTask isEmpty stop if there are no items in first syncTask remove the task and restart the process. */ private func prepare(){ // I use a database query to store & retrieve pendingTasks guard !pendingTasks.isEmpty else{ // todo no more data to sync isSyncing = false // syncing process ended // Notify app that your long running task has finished (UIApplication.sharedApplication().delegate as? AppDelegate)?.endBackgroundSyncTask() return } isSyncing = true // we are in syncing process // Notify app that our long running task has begun (UIApplication.sharedApplication().delegate as? AppDelegate)?.beginBackgroundRestoreTask() // Call function to start the first upload uploadFileOrData() } } /** upload the files & data from array recursively */ private func uploadFileOrData(){ var task = pendingTasks[0] let imageUrl = task.imageUrl let audioUrl = task.audioUrl let tags = task.tags.reduce(""){ prev, next in if prev.isEmpty{ return next.text } return "\(prev),\(next.text)" } let form : (MultipartFormData) -> () = { data in if imageUrl.checkResourceIsReachableAndReturnError(nil){ data.appendBodyPart(fileURL: imageUrl, name: "image") } if audioUrl.checkResourceIsReachableAndReturnError(nil){ data.appendBodyPart(fileURL: audioUrl, name: "audio") } data.appendBodyPart(data: tags.dataUsingEncoding(NSUTF8StringEncoding,allowLossyConversion: false)!, name: "tags") } upload(.POST, Api.fileUploadUrl, multipartFormData: form ,encodingCompletion: { // Call function to process the response self.processUploadFileResponse($0) }) } private func processUploadFileResponse(result: Manager.MultipartFormDataEncodingResult){ switch result { case .Success(let upload, _, _): // YOUR LOGIN ON SUCCESS // MOVE TO NEXT LOCATION self.moveToNextTask() case .Failure(_): // YOUR LOGIN ON FALIURE // MOVE TO NEXT LOCATION self.moveToNextTask() } } private func moveToNextTask(){ // DELETE pendingTasks[0] & CALL prepare() function // If you want to repeat after every 10 MINUTE // Then wrap your function call 'prepare()' inside dispatch_after dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(10 * 60 * Double(NSEC_PER_SEC)) // 10 * 60 to convert seconds into minute ), dispatch_get_main_queue(), { self.prepare() }) } 

AppDelegate类

 // bind the alamofire backgroundCompletionHandler func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { // NSLog("handle events for background: \(identifier)") if identifier == SyncMangerIdentifier{ SyncManager.instance.backgroundCompletionHandler = completionHandler } } // Identifier for long running background task for SyncManager class var backgroundSyncTask: UIBackgroundTaskIdentifier? // Call this at the beginning of syncing func beginBackgroundSyncTask() { backgroundRestoreTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({ self.endBackgroundRestoreTask() }) } // Call this when syncing process ends func endBackgroundSyncTask() { guard backgroundSyncTask != nil else { return } UIApplication.sharedApplication().endBackgroundTask(self.backgroundSyncTask!) self.backgroundSyncTask = UIBackgroundTaskInvalid } 

注意

为了在您的应用程序进入后台时继续请求,您可能需要从应用程序的function部分启用BackGroundFetchMode

既然你想在所有的ViewControllers(VC)中调用上传的方法,一种方法是:

 extension UIViewController { func uploadData(parameters) ->Bool { return true/false; } } 

然后在所有ViewController(VC)中,您可以调用viewDidLoad中的uploadData方法或特定的函数,如: –

 if(self.uploadData(parameters)) // if true method is called ie new objects available to upload or 10mins have passed as per your requirement { } 

第二种方法是定义NSTimer部分,检查是否在AppDelegate中传递了10分钟,并创build一个空的Swift文件,该文件不会在AppDelegate中上传并调用didFinishLaunchingWithOptions中的方法。

有很多方法可以解决这个问题,但这取决于您的应用程序需要如何实现stream程。

注意: –使用NSURLSessionUploadTask – >上传和NSTimer – >检查是否已经过去10分钟