Swift后台同步管理器

时间:2016-07-25 08:42:01

标签: ios swift

我想制作一个每10分钟上传多部分数据的上传管理器单例。上传本身很清楚但是如何创建一个在后面这个时间间隔上传数据的类?

只需指定:

我要上传的数据是一个包含对象数组的模型。每个对象都有一个标志,当设置了这个标志时,对象就可以上传了。整个“同步功能”应该被调用一次并且每10分钟重复一次,无论我在哪个ViewController上。有谁知道我怎么能这样做?

2 个答案:

答案 0 :(得分:6)

代码使用了一些外部框架。它基于递归。

  1. delegated way // for networking
  2. *上述框架并不重要。我只是用它来加快开发过程。

      

    同步管理器

    <button>
      

    AppDelegate类

    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, _, _):
    
               // PERFORM ACTION ON SUCCESS
    
               // MOVE TO NEXT LOCATION
                self.moveToNextTask()
    
            case .Failure(_):
                // PERFORM ACTION 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()
                    })
    
                }
    
      

    请注意

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

答案 1 :(得分:0)

由于您希望在所有ViewControllers(VC)中调用上传方法,因此一种方法是: -

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

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

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

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

有很多方法可以解决这个问题,但这取决于您的应用程序中流量的发生方式。

注意: - 使用 NSURLSessionUploadTask - &gt;上传和 NSTimer - &gt;检查是否已经过了10分钟