it's coredatastack file. when run project concurrency debugging app crashes right after pin added. think cause try access data in different thread thread in context created. fix need of data access happens in same thread thread in context created. wrong?
run project -com.apple.coredata.concurrencydebug 1
import coredata struct coredatastack { // mark: - properties private let model: nsmanagedobjectmodel internal let coordinator: nspersistentstorecoordinator private let modelurl: url internal let dburl: url internal let persistingcontext: nsmanagedobjectcontext internal let backgroundcontext: nsmanagedobjectcontext let context: nsmanagedobjectcontext // mark: - initializers init?(modelname: string) { // assumes model in main bundle guard let modelurl = bundle.main.url(forresource: modelname, withextension: "momd") else { print("unable find \(modelname)in main bundle") return nil } self.modelurl = modelurl // try create model url guard let model = nsmanagedobjectmodel(contentsof: modelurl) else { print("unable create model \(modelurl)") return nil } self.model = model // create store coordinator coordinator = nspersistentstorecoordinator(managedobjectmodel: model) // create persistingcontext (private queue) , child 1 (main queue) // create context , add connect coordinator persistingcontext = nsmanagedobjectcontext(concurrencytype: .privatequeueconcurrencytype) persistingcontext.persistentstorecoordinator = coordinator context = nsmanagedobjectcontext(concurrencytype: .mainqueueconcurrencytype) context.parent = persistingcontext // create background context child of main context backgroundcontext = nsmanagedobjectcontext(concurrencytype: .privatequeueconcurrencytype) backgroundcontext.parent = context // add sqlite store located in documents folder let fm = filemanager.default guard let docurl = fm.urls(for: .documentdirectory, in: .userdomainmask).first else { print("unable reach documents folder") return nil } self.dburl = docurl.appendingpathcomponent("model.sqlite") // options migration let options = [nsinfermappingmodelautomaticallyoption: true,nsmigratepersistentstoresautomaticallyoption: true] { try addstorecoordinator(nssqlitestoretype, configuration: nil, storeurl: dburl, options: options [nsobject : anyobject]?) } catch { print("unable add store @ \(dburl)") } } // mark: - utils func addstorecoordinator(_ storetype: string, configuration: string?, storeurl: url, options : [nsobject:anyobject]?) throws { try coordinator.addpersistentstore(oftype: nssqlitestoretype, configurationname: nil, at: dburl, options: nil) } } // mark: - coredatastack (removing data) internal extension coredatastack { func dropalldata() throws { // delete objects in db. won't delete files, // leave empty tables. try coordinator.destroypersistentstore(at: dburl, oftype: nssqlitestoretype , options: nil) try addstorecoordinator(nssqlitestoretype, configuration: nil, storeurl: dburl, options: nil) } } // mark: - coredatastack (batch processing in background) extension coredatastack { typealias batch = (_ workercontext: nsmanagedobjectcontext) -> () func performbackgroundbatchoperation(_ batch: @escaping batch) { backgroundcontext.perform() { batch(self.backgroundcontext) // save parent context, normal saving // can work { try self.backgroundcontext.save() } catch { fatalerror("error while saving backgroundcontext: \(error)") } } } } // mark: - coredatastack (save data) extension coredatastack { func save() { context.performandwait() { if self.context.haschanges { { try self.context.save() } catch { fatalerror("error while saving main context: \(error)") } self.persistingcontext.perform() { { try self.persistingcontext.save() } catch { fatalerror("error while saving persisting context: \(error)") } } } } } func autosave(_ delayinseconds : int) { if delayinseconds > 0 { { try self.context.save() print("autosaving") } catch { print("error while autosaving") } let delayinnanoseconds = uint64(delayinseconds) * nsec_per_sec let time = dispatchtime.now() + double(int64(delayinnanoseconds)) / double(nsec_per_sec) dispatchqueue.main.asyncafter(deadline: time) { self.autosave(delayinseconds) } } } }
make sure make ui changes in main thread.
Comments
Post a Comment