iOS applicationWillResignActive 任​​务在应用再次激活之前不会执行

Posted

技术标签:

【中文标题】iOS applicationWillResignActive 任​​务在应用再次激活之前不会执行【英文标题】:iOS applicationWillResignActive task not performed until app becomes active again 【发布时间】:2018-06-05 07:26:43 【问题描述】:

我正在尝试使用applicationWillResignActive() 以便在应用程序进入后台之前将一些数据同步到我的Firestore 数据库。

func applicationWillResignActive(_ application: UIApplication) 
        self.uploadWantToPlay()

当我从applicationWillResignActive() 调用我的上传函数时,它会运行,但在下次应用程序激活之前,不会向Firestore 添加任何数据。

当我出于测试目的而不是从我的ViewControllers 之一运行相同的功能时,数据会立即添加到Firestore

我也尝试从applicationDidEnterBackground() 调用该函数,我尝试在它自己的DispatchQueue 中运行它。但结果是一样的。

当用户即将离开应用程序并让它正确执行数据库同步时,我该如何运行此功能?

处理数据库同步的函数;

func uploadWantToPlay() 
    print ("Inside uploadWantToPlay")
    if let wantToPlay = User.active.wantToPlayList 
        if let listEntries = wantToPlay.list_entries 
            let cleanedEntries = listEntries.compactMap( (entry: ListEntry) -> ListEntry? in
                if entry.game?.first_release_date != nil 
                    return entry
                 else 
                    return nil
                
            )
            let gamesToUpload = cleanedEntries.filter 
                $0.game!.first_release_date! > Int64(NSDate().timeIntervalSince1970 * 1000)
            
            DatabaseConnection().writeWantToPlayToDatabase(user: User.active,wantToPlay: gamesToUpload)
        
    


func writeWantToPlayToDatabase(user: User, wantToPlay: [ListEntry]) 
    firebaseSignIn()
    let deviceId = ["\(user.deviceId)": "Device ID"]
    for entry in wantToPlay 
        let wantToPlayGameRef = fireStore.collection(WANTTOPLAY).document("\(entry.game!.id!)")

        wantToPlayGameRef.updateData(deviceId) (err) in
            if err != nil 
                wantToPlayGameRef.setData(deviceId) (err) in
                    if let err = err 
                        Events().logException(withError: err, withMsg: "DatabaseConnection-writeWantToPlayToDatabase(user, [ListEntry]) Failed to write to database")
                     else 
                        print("Document successfully written to WantToPlayGames")
                    
                
             else 
                print("Document successfully updated in WantToPlayGames")
            
        
    

【问题讨论】:

您需要致电beginBackgroundTaskWithExpirationHandler 【参考方案1】:

根据Apple documentation

移至后台的应用程序应将自己置于 尽可能快地进入静止状态,以便它们可以暂停 由系统。如果您的应用程序正在执行一项任务并且需要 完成该任务的额外时间很少,它可以调用 beginBackgroundTaskWithName:expirationHandler: 或 beginBackgroundTaskWithExpirationHandler:UIApplication 的方法 对象请求一些额外的执行时间。调用任何一个 这些方法会暂时延迟您的应用程序的暂停,给它 一点额外的时间来完成它的工作。完成这项工作后, 你的应用必须调用 endBackgroundTask: 方法让系统 知道已经完成,可以暂停了。

因此,您需要在这里做的是在您的应用暂停时执行一个有限长度的任务。这将为您的应用赢得足够的时间来将您的记录同步到服务器。

一个例子 sn-p:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate 

    var window: UIWindow?
    var backgroundTask: UIBackgroundTaskIdentifier!

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 
        // Override point for customization after application launch.
        return true
    

    func applicationWillResignActive(_ application: UIApplication) 
        self.registerBackgroundTask()

        // Do your background work here
        print("Do your background work here")

        // end the task when work is completed
        self.endBackgroundTask()
    

    func registerBackgroundTask() 
        self.backgroundTask = UIApplication.shared.beginBackgroundTask  [weak self] in
            self?.endBackgroundTask()
        
        assert(self.backgroundTask != UIBackgroundTaskInvalid)
    

    func endBackgroundTask() 
        print("Background task ended.")
        UIApplication.shared.endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    


有关更多信息,请参阅此article。

【讨论】:

感谢您的回复。当我尝试这个时,似乎什么都没有发生。没有数据写入数据库,我没有看到你的 endBackgroundTask 的日志打印,我也看不到我自己的上传功能的任何日志打印。当我单步执行代码时,我从不输入任何上传函数或 endBackgroundTask 函数。 抱歉,sn-p 中存在错误。我已经更新了代码。另外,如果可以粘贴您的上传方法的代码,将更容易找到解决方案 这使它表现得像我原来的方法一样,函数运行但数据库在下次应用程序激活时更新。我使用相关功能在我的问题中添加了更多的 sn-ps。 (代码有点乱,直到我开始工作之前我才费心去清理它) 这里的问题是,一旦数据同步,您需要调用 endBackgroundTask。您是否定义了任何完成处理程序来告诉您调用已完成? 您的解决方案与信号量相结合解决了我的问题。非常感谢您的帮助:D

以上是关于iOS applicationWillResignActive 任​​务在应用再次激活之前不会执行的主要内容,如果未能解决你的问题,请参考以下文章

IO复用阻塞IO非阻塞IO同步IO异步IO

四种IO模型‘阻塞IO/非阻塞IO/信号驱动IO/异步IO‘

5种IO模型阻塞IO和非阻塞IO同步IO和异步IO

网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别