2016-07-25 3 views
3

Я хочу создать диспетчер загрузки Singleton, который загружает данные из нескольких частей каждые 10 минут. Загрузка сама по себе ясна, но как я могу создать класс, который загружает данные в этот временной интервал в фоновом режиме?Быстрое управление синхронизацией фонового изображения

Просто указать:

Данные, которые я хочу, чтобы загрузить это модель, которая имеет массив объектов. Каждый из объектов имеет флаг, и когда этот флаг установлен, объект готов для загрузки. Вся эта функция «Синхронизация» должна вызываться один раз и повторяться каждые 10 минут, независимо от того, на каком я ViewController я. Кто-нибудь знает, как я могу это сделать?

ответ

4

Код использует некоторые внешние рамки. Он основан на рекурсии.

  1. Alamofire // для сетей

* Выше рамки не важно. Я просто использовал его для закрепления процесса разработки.

Sync Manager

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 
} 

Примечание

Чтобы продолжить запрос, когда приложение входит в фоне может понадобиться включить BackGroundFetchMode из Capabilities секции приложения

0

Поскольку вы хотите метод загрузки называться во всех ViewControllers (VCS) Один из подходов: -

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

Тогда во всех ViewControllers (VCS), вы можете вызвать метод uploadData в viewDidLoad или в конкретных функции, как: -

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 ли прошло 10 минут в AppDelegate и создать пустой файл Swift, который делает Выгрузка и вызвать метод в didFinishLaunchingWithOptions в AppDelegate.

Существует много способов сделать это, но это зависит от того, как поток должен произойти в вашем приложении.

Примечание: - Использование NSURLSessionUploadTask -> Для того, чтобы загрузить и NSTimer -> Для того, чтобы проверить, является ли прошло 10 минут

+0

Спасибо за ваш ответ! Но я не хочу вызывать функцию в каждом ViewController. Я хочу вызвать его один раз на первом ViewController, а затем позвонить себе каждые 10 минут – Thomas

+0

, тогда вы можете сделать второй подход – MShah

+0

это для синхронизации, я думаю, что этот подход приведет к потреблению большого количества пользовательских ресурсов и пропускной способности, если он продолжит для загрузки каждые 10 минут. – MShah

Смежные вопросы