作为 UIBackgroundTask 运行时,后台线程上的核心数据迁移失败
Posted
技术标签:
【中文标题】作为 UIBackgroundTask 运行时,后台线程上的核心数据迁移失败【英文标题】:Core-Data migration on background thread failing when running as a UIBackgroundTask 【发布时间】:2012-01-25 12:05:58 【问题描述】:我的代码:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
@autoreleasepool
// Now on a background thread
// Setup background task
__block UIBackgroundTaskIdentifier bgTask;
void (^finishBackgroundTask)(void) = ^(void)
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
;
// Start background task
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:finishBackgroundTask];
// The method below migrates a core data database and takes ages
[MyClass migrateCoreDataStuff];
finishBackgroundTask();
);
我得到的错误是NSUnderlyingException = "Fatal error. The database at /var/mobile/Applications/55B83D5F-CCF5-438E-BECA-B97DB5505541/Documents/Blah.sqlite is corrupted. SQLite error code:11, 'database disk image is malformed'";
仅当以下全部为真时才会发生迁移错误: * 迁移在后台线程上 * 迁移作为 UIBackgroundTask 运行 * 我在设备上运行,不是模拟器
我正在运行 ios 4.3.5,为 iOS 4.0 构建。
【问题讨论】:
哎呀...想通了。永远不要从主线程以外的任何地方调用 UIKit 中的任何东西。在这种情况下,我正在启动一个后台任务 ([[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:]
),从而从后台线程向我的 UIApplication 实例发送消息。这是坏。
__block UIBackgroundTaskIdentifier bgTask; void (^finishBackgroundTask)(void) = ^(void) [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; ; bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:finishBackgroundTask];dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ @autoreleasepool [MyClass migrateCoreDataStuff]; dispatch_async(dispatch_get_main_queue(), finishBackgroundTask); );
这不太可能是根本问题。 beginBackgroundTaskWithExpirationHandler
在文档中被特别标记为线程安全。你可能只是在掩盖真正的问题。
你说得对,上面的代码实际上是行不通的(我有点草率了)。
【参考方案1】:
没有看到migrateCoreDataStuff
的内容,很难看出确切的问题。然而,非主线程上的 Core Data 是一个棘手的问题。阅读http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html。您可能至少需要为新线程提供一个单独的托管对象上下文。
【讨论】:
是的,那个方法很大,我不能在这里发布,但本质上它是从media.pragprog.com/titles/mzcd/code/ProgressiveMigration/… 逐步迁移的(我按照你的建议使用了一个单独的上下文,当 migrateCoreDataStuff 正在运行时,什么都没有应用程序中的 else 可能正在访问持久存储) 简单看一下代码表明您正在共享托管对象上下文?至少,它只在一个地方被创建,并且将来每次调用都会返回该引用?以上是关于作为 UIBackgroundTask 运行时,后台线程上的核心数据迁移失败的主要内容,如果未能解决你的问题,请参考以下文章
处理 UIBackgroundTask Expiration 正在停止我的 beaconRanging 方法
将 Microsoft Access 作为计划任务运行后退出
如何在 CMake 中构建过程后复制目标的所有运行时依赖项?