NSInternalInconsistencyException when querying Core Data while iOS is migrating iCloud transaction logs -
i started seeing error reported on crashlytics after updating model in ios app (lightweight migration, since data store synced via icloud). issue seems affect ~2-3% of sessions , found difficult reproduce in test environment.
here error (stack trace of crashing thread):
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 ...and here ios thread performing icloud transaction logs migration
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 i believe code follows best practices core data concurrency (see relevant extracts swift code below). in particular
- the
managedobjectcontextconfiguredprivatequeueconcurrencytype - all calls core data apis wrapped in
managedobjectcontext.performblock() managedobjectcontextsaved , reset instorewillchangewhat missing?
here code crashes
private func executesync(request: nsfetchrequest) -> [anyobject]? { var results: [anyobject]? if let moc = managedobjectcontext { moc.performblockandwait({ () -> void in { try results = moc.executefetchrequest(request) // crashes here } catch let error nserror { error("error executefetchrequest of wtvcoredatahelper threw error \(error)") } }) } return results } setup of of 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 error creating or loading application's saved data." { try coordinator!.addpersistentstorewithtype(nssqlitestoretype, configuration: nil, url: url, options: options) } catch var error nserror { coordinator = nil var dict = [nsobject:anyobject]() dict[nslocalizeddescriptionkey] = "failed initialize 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 managed object context application (which bound persistent store coordinator application.) property optional since there legitimate error conditions cause creation of context fail. let coordinator = self.persistentstorecoordinator if coordinator == nil { return nil } var managedobjectcontext = nsmanagedobjectcontext(concurrencytype: nsmanagedobjectcontextconcurrencytype.privatequeueconcurrencytype) managedobjectcontext.persistentstorecoordinator = coordinator // set mergepolicy prioritise external inputs let mergepolicy = nsmergepolicy(mergetype:nsmergepolicytype.mergebypropertystoretrumpmergepolicytype ) managedobjectcontext.mergepolicy = mergepolicy return managedobjectcontext }() relevant delegate methods:
@objc func storewillchange(notification: nsnotification) { if let moc = self.managedobjectcontext { moc.performblockandwait({ () -> void in if moc.haschanges { { try moc.save() } catch let error nserror { error("error unresolved error while saving context \(error), \(error.userinfo)") } catch { fatalerror() } } moc.reset() }) } } update: reproduced problem once on device model had been updated latest version - not sure lightweight migration contributing factor.
Comments
Post a Comment