当 iOS 应用程序在前台时,如何在后台 运行 操作

How to run operations in background while an iOS application is in foreground

我在文档目录中有一个 JSON 文件,其中填充了字符串数据。在应用程序的用户界面中有一个 UIButton。按下按钮时,一个新字符串将附加到 JSON 文件中。

现在我正在寻找可以帮助我使用 swift 将这些字符串(从 JSON 文件)发送到服务器的任何 iOS 服务。而且这个服务应该完全独立于我的代码。 关键是当我按下一个 UIButton 时,第一步是将一个字符串保存到 JSON 文件中,然后服务应该获取该字符串并将其发送到服务器(如果互联网可用)。

当一个字符串发送成功后,它应该从JSON文件中删除。 该服务应每 30 秒跟踪一次是否有任何字符串保存到 JSON 文件中,然后将其发送到服务器。

我用 Google 搜索并找到了 background fetch,但它会自动触发 performFetchWithCompletionHandler 函数,我不知道 iOS 何时会触发它。我想每隔 30 秒自己触发一次这种服务。

查看 iOS 的 Apple 应用程序编程指南的 Background Execution 部分。

UIApplication 提供了一个接口来启动和结束后台任务 UIBackgroundTaskIdentifier.

在您的 AppDelegate 的顶层,创建一个 class 级任务标识符:

var backgroundTask = UIBackgroundTaskInvalid

现在,使用您希望完成的操作创建您的任务,并实施您的任务在过期前未完成的错误情况:

backgroundTask = application.beginBackgroundTaskWithName("MyBackgroundTask") {
    // This expirationHandler is called when your task expired
    // Cleanup the task here, remove objects from memory, etc

    application.endBackgroundTask(self.backgroundTask)
    self.backgroundTask = UIBackgroundTaskInvalid
}

// Implement the operation of your task as background task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // Begin your upload and clean up JSON
    // NSURLSession, AlamoFire, etc

    // On completion, end your task
    application.endBackgroundTask(self.backgroundTask)
    self.backgroundTask = UIBackgroundTaskInvalid
}

请参考 NSURLSessionUploadTask 可能对您有帮助。

我所做的只是使用上面日航讨论的方法。

这是我用过的三种方法

    func reinstateBackgroundTask() {
        if updateTimer != nil && (backgroundTask == UIBackgroundTaskInvalid) {
            registerBackgroundTask()
           }
    }
    func registerBackgroundTask() {
        backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
            [unowned self] in
            self.endBackgroundTask()
        }
        assert(backgroundTask != UIBackgroundTaskInvalid)
    }

    func endBackgroundTask() {
        NSLog("Background task ended.")
        UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    }

其中 updateTimer 的类型为 NSTIMER class 以上函数在我自己创建的class中命名为"syncService" 这个 class 有一个初始化器

init(){
  NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.reinstateBackgroundTask), name: UIApplicationDidBecomeActiveNotification, object: nil)

        updateTimer = NSTimer.scheduledTimerWithTimeInterval(30.0, target: self, selector: #selector(self.syncAudit), userInfo: nil, repeats: true)
        registerBackgroundTask()

 }

然后我就调用这个class,整个问题就解决了。

 DispatchQueue.global(qos: .background).async { // sends registration to background queue

 }

这是 JAL

的 swift 4 版答案
  extension UIApplication {
  /// Run a block in background after app resigns activity
   public func runInBackground(_ closure: @escaping () -> Void, expirationHandler: (() -> Void)? = nil) {
       DispatchQueue.main.async {
        let taskID: UIBackgroundTaskIdentifier
        if let expirationHandler = expirationHandler {
            taskID = self.beginBackgroundTask(expirationHandler: expirationHandler)
        } else {
            taskID = self.beginBackgroundTask(expirationHandler: { })
        }
        closure()
        self.endBackgroundTask(taskID)
    }
  }

  }

使用示例

UIApplication.shared.runInBackground({
        //do task here
    }) {
       // task after expiration.
    }