我正在寻找解决这个难题的最佳实践:
我的应用程序具有文件导入/导出功能以及核心数据。这意味着,当我将文件导入应用程序时,我会在核心数据中创建一个条目,并将该文件复制到应用程序的私人目录中。接下来,我处理这个文件,并在应用程序中为不同的目的创建一些其他文件。对于iPhone 3G上的每个文件,这些繁重的计算大约需要0.2秒。
这意味着我在进口时要处理某种"交易"。这一切都是使用一个大的FileImportOperation : NSOperation
完成的,它迭代所有必须导入的文件,并对列表中的每个文件执行繁重的导入工作。
问题是:后台线程和NSOperations在没有事先警告的情况下仅在一纳秒内被操作系统杀死。只有主线程有5秒的时间来快速保存一些工作并退出。
我如何确保我永远不会中途导入文件,使应用程序处于损坏或垃圾状态?
在我看来,邪恶的问题是,当用户退出应用程序时,后台线程(包括NSOperation)会立即被杀死,而没有任何机会清理。我试图通过只在所有这些文件都已成功创建和保存的情况下编写托管对象来弥补这一点(请记住:每个导入的文件都会被复制并以不同的方式处理多次,用于不同的事情)。但我仍然可能以不完整的导入结束,破坏用户的磁盘。
我对该问题的临时解决方案如下:拥有NSOperationQueue的对象注册UIApplicationWillTerminateNotification
通知。当它收到它时,将-cancelAllOperations
发送到队列,队列将所有正在运行的操作标记为已取消。
在这一点上我被卡住了。现在,我的NSOperations被标记为已取消,但它们仍然必须完成当前的内部运行循环并停止
我的下一个想法是强制主线程等待所有操作完成,然后让-applicationWillTerminate:
返回。
我希望能得到一些关于如何实现安全交易的专业建议,以防止在后台导入时使应用程序处于损坏状态。
您是否可以以一种即使不是原子的也至少可以重新启动的方式执行导入操作?例如,可重新启动的文件移动可能看起来像:
搜索并删除目标文件夹中的所有文件"*.tmp"。在源文件夹中查找需要复制的文件-找到一个"data.DB"将文件作为"data.DB.tmp"复制到目标文件夹将"data.DB.tmp"重命名为"data.DB"
在应用程序启动时,搜索并删除所有文件"*.tmp"
再加上基于事务的"核心数据"数据库更新(即可以回滚),这种方法能解决您的问题吗?
Rgds,Martin
如果您使用的是iOS 4.x,您尝试过beginBackgroundTaskWithExpirationHandler
吗?
backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
[app endBackgroundTask:backgroundTaskIdentifier];
backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
});
}];