在我的iOS应用程序中更新模型后,我开始在Crashlytics上看到此错误报告(轻量级迁移,因为数据存储通过iCloud同步)。这个问题似乎影响了2-3%的会议,我发现在测试环境中很难再现。
这是错误(崩溃线程的堆栈跟踪):
Thread : Crashed: com.twitter.crashlytics.ios.exception
0 webtv 0x000000010031ad28 CLSProcessRecordAllThreads + 4298337576
1 webtv 0x000000010031ad28 CLSProcessRecordAllThreads + 4298337576
2 webtv 0x000000010031b1d8 CLSProcessRecordAllThreads + 4298338776
3 webtv 0x0000000100305c08 CLSHandler + 4298251272
4 webtv 0x0000000100318f20 __CLSExceptionRecord_block_invoke + 4298329888
5 libdispatch.dylib 0x00000001994c9770 _dispatch_client_callout + 16
6 libdispatch.dylib 0x00000001994d49c4 _dispatch_barrier_sync_f_invoke + 100
7 webtv 0x0000000100318ab8 CLSExceptionRecord + 4298328760
8 webtv 0x00000001003188d0 CLSExceptionRecordNSException + 4298328272
9 webtv 0x0000000100318530 CLSTerminateHandler() + 4298327344
10 libc++abi.dylib 0x0000000198372f44 std::__terminate(void (*)()) + 16
11 libc++abi.dylib 0x0000000198372fd0 std::set_new_handler(void (*)()) + 90
12 libobjc.A.dylib 0x0000000198cdc1a4 _destroyAltHandlerList + 10
13 libdispatch.dylib 0x00000001994c9784 _dispatch_client_callout + 36
14 libdispatch.dylib 0x00000001994d49c4 _dispatch_barrier_sync_f_invoke + 100
15 CoreData 0x0000000183e53b08 -[NSManagedObjectContext performBlockAndWait:] + 252
16 webtv 0x00000001001320ec WTVCoreDataHelper.(executeSync in _B3CAA6076B08D24EA69CA58785DFF9DB)(NSFetchRequest, error : inout NSError?) -> [AnyObject]? (WTVCoreDataHelpers.swift:136)
17 webtv 0x00000001001390f0 WTVCoreDataHelper.defaultProfile() -> WTVProfile? (WTVCoreDataHelpers.swift:529)
18 webtv 0x00000001001335c0 WTVCoreDataHelper.(defaultProfileIfNil in _B3CAA6076B08D24EA69CA58785DFF9DB)(WTVProfile?) -> WTVProfile? (WTVCoreDataHelpers.swift:204)
19 webtv 0x0000000100132de8 WTVCoreDataHelper.(systemFolder in _B3CAA6076B08D24EA69CA58785DFF9DB)(WTVProfile?) -> WTVFolder? (WTVCoreDataHelpers.swift:179)
20 webtv 0x00000001001358a8 WTVCoreDataHelper.homePage(profile : WTVProfile?) -> WTVPage? (WTVCoreDataHelpers.swift:345)
21 webtv 0x0000000100273bec SWWebBrowserViewController.homePageUrl.getter (SWWebBrowserViewController.swift:97)
22 webtv 0x00000001002607f4 SWBrowserHomeButton.evaluateForChangeOfState(NSURL?) -> () (SWBrowserControlButtons.swift:94)
23 webtv 0x000000010025e5b8 SWBrowserControlButton.store(FASFluxStore!, didEmitChangeNotification : NSNotification!) -> () (SWBrowserControlButtons.swift:36)
24 webtv 0x000000010025e630 @objc SWBrowserControlButton.store(FASFluxStore!, didEmitChangeNotification : NSNotification!) -> () (SWBrowserControlButtons.swift)
[...]
49 GraphicsServices 0x000000018ef98088 GSEventRunModal + 180
50 UIKit 0x00000001896caf60 UIApplicationMain + 204
51 webtv 0x00000001002c0c60 main (AppDelegate.swift:19)
52 libdyld.dylib 0x00000001994fa8b8 start + 4
...这是执行一些iCloud事务日志迁移的iOS线程
Thread : com.apple.coredata.ubiquity.entry.pq
0 libsystem_kernel.dylib 0x0000000199608c6c semaphore_wait_trap + 8
1 libdispatch.dylib 0x00000001994da684 _dispatch_semaphore_wait_slow + 244
2 Foundation 0x00000001850fed94 -[NSFileCoordinator(NSPrivate) _blockOnAccessClaim:] + 380
3 Foundation 0x00000001850ff8b0 -[NSFileCoordinator(NSPrivate) _coordinateReadingItemAtURL:options:error:byAccessor:] + 440
4 Foundation 0x00000001850fd8fc -[NSFileCoordinator coordinateReadingItemAtURL:options:error:byAccessor:] + 72
5 CoreData 0x0000000183f23280 -[PFUbiquityFileCoordinator coordinateReadingItemAtLocation:options:retryOnError:error:byAccessor:] + 140
6 CoreData 0x0000000183f3c27c -[PFUbiquityLocation fileExistsAtLocationWithLocalPeerID:error:] + 324
7 CoreData 0x0000000183f77790 -[PFUbiquitySafeSaveFile existsInCloud] + 88
8 CoreData 0x0000000183f4b958 -[PFUbiquityMigrationManager migrateTransactionLogs:andBaselineIfNecessaryForStoreName:peerID:error:] + 1328
9 CoreData 0x0000000183f5db18 -[PFUbiquitySetupAssistant initializeBaselineForStore:error:] + 2576
10 CoreData 0x0000000183f5a3b4 -[PFUbiquitySetupAssistant finishSetupForStore:error:] + 2324
11 CoreData 0x0000000183f59828 -[PFUbiquitySetupAssistant finishSetupWithRetry:] + 152
12 CoreData 0x0000000183f222a8 __57-[PFUbiquitySwitchboardEntry executeBlockOnPrivateQueue:]_block_invoke + 64
13 libdispatch.dylib 0x00000001994c97b0 _dispatch_call_block_and_release + 24
14 libdispatch.dylib 0x00000001994c9770 _dispatch_client_callout + 16
15 libdispatch.dylib 0x00000001994d575c _dispatch_queue_drain + 864
16 libdispatch.dylib 0x00000001994cd274 _dispatch_queue_invoke + 464
17 libdispatch.dylib 0x00000001994c9770 _dispatch_client_callout + 16
18 libdispatch.dylib 0x00000001994d7bb0 _dispatch_root_queue_drain + 2140
19 libdispatch.dylib 0x00000001994d734c _dispatch_worker_thread3 + 112
20 libsystem_pthread.dylib 0x00000001996e9478 _pthread_wqthread + 1092
21 libsystem_pthread.dylib 0x00000001996e9028 start_wqthread + 4
我相信我的代码遵循核心数据并发的最佳实践(请参阅下面Swift
代码的相关摘录)。特别是
managedObjectContext
配置了PrivateQueueConcurrencyType
managedObjectContext.performBlock()
managedObjectContext
已保存并在storeWillChange
我缺少什么?
以下是崩溃的代码
private func executeSync(request: NSFetchRequest) -> [AnyObject]? {
var results: [AnyObject]?
if let moc = managedObjectContext {
moc.performBlockAndWait({ () -> Void in
do {
try results = moc.executeFetchRequest(request) // Crashes here
} catch let error as NSError {
ERROR("ERROR executeFetchRequest of WTVCoreDataHelper threw an error \(error)")
}
})
}
return results
}
设置persistentStoreCoordinator
,managedObjectContext
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("WebVideoCast.sqlite")
var options = [NSObject:AnyObject]()
options[NSPersistentStoreUbiquitousContentNameKey] = kConstants.ubiquityStoreIdentifier
options[NSMigratePersistentStoresAutomaticallyOption] = true
options[NSInferMappingModelAutomaticallyOption] = true
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options)
} catch var error as NSError {
coordinator = nil
var dict = [NSObject:AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = NSError(domain: kConstants.errorDomain, code: 9999, userInfo: dict)
ERROR("Unresolved error \(error), \(error.userInfo)")
abort()
} catch {
fatalError()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
// Set the MergePolicy to prioritise external inputs
let mergePolicy = NSMergePolicy(mergeType:NSMergePolicyType.MergeByPropertyStoreTrumpMergePolicyType )
managedObjectContext.mergePolicy = mergePolicy
return managedObjectContext
}()
相关代表方法:
@objc func storeWillChange(notification: NSNotification) {
if let moc = self.managedObjectContext {
moc.performBlockAndWait({ () -> Void in
if moc.hasChanges {
do {
try moc.save()
} catch let error as NSError {
ERROR("ERROR Unresolved error while saving context \(error), \(error.userInfo)")
} catch {
fatalError()
}
}
moc.reset()
})
}
}
更新:我刚刚在模型更新到最新版本的设备上重现了一次 - 所以我真的不确定轻量级迁移是否是一个影响因素。