当我尝试将新对象保存到核心数据中时,当我尝试保存上下文时,我收到此错误并崩溃:
libc++abi.dylib: terminating with uncaught exception of type NSException
我使用相同的方法将新创建的托管对象保存在许多其他视图控制器中,除此之外所有工作正常。当我改变这一行时,问题就出现了:
var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
来自AppDelegate中的.mainQueueConcurrencyType。
这是我在AppDel中的持久存储协调器设置:
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
这是导致崩溃的一系列功能:
//get a new model for the components, same context, new FRC
purchaseOrderModel = StockModel()
purchaseOrderModel.setupManagedObjectContext()
purchaseOrderModel.tableView = tableView
if purchaseOrder == nil {
//delegate?.editModeStateChange(editing: true)
purchaseOrder = purchaseOrderModel.savePurchaseOrderWith("", supplier: nil, issueDate: Date(), deliveryDate: Date(), deliveryStatus: false)
delegate?.newItemAdded()
creatingNewPurchaseOrder = true
}
致电
func savePurchaseOrderWith(_ poId: String?, supplier: NSManagedObject?, issueDate: Date, deliveryDate: Date, deliveryStatus: Bool? = nil) -> NSManagedObject {
let newPurchaseOrder = NSEntityDescription.insertNewObject(forEntityName: "Purchase_Order", into: context)
newPurchaseOrder.setValue(poId, forKey: "po_id")
newPurchaseOrder.setValue(issueDate, forKey: "issue_date")
newPurchaseOrder.setValue(deliveryDate, forKey: "est_delivery_date")
newPurchaseOrder.setValue(supplier, forKey: "supplier")
newPurchaseOrder.setValue(deliveryStatus, forKey: "delivered")
_ = doSaveContext()
return newPurchaseOrder
}
doSaveContext:
func doSaveContext() -> Bool {
do {
try context.save() //editing POs makes it crash here after changing the created context in app delegate
return true
} catch let error as NSError {
print("Error saving context after delete \(error.localizedDescription)")
return false
}
}
我在try context.save()
自从我参与这个项目以来已经过了几个月,但这就是停止开发的基础,所以帮助会很棒。奇怪的是,创建一个以doSaveContext()结尾的新空对象(比如交付,新产品等)的每个其他路径都可以正常工作。
很高兴发布额外信息等。
更新1:添加异常断点时,它在我的模型类的这个函数中断开:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type{
case NSFetchedResultsChangeType.insert:
//note that for insert we insert a row at _newIndexPath_
if let insertIndexPath = newIndexPath {
self.tableView.insertRows(at: [insertIndexPath], with: UITableViewRowAnimation.fade)
}
case NSFetchedResultsChangeType.delete:
//note that for delete we delete the row at _indexPath_
if let deleteIndexPath = indexPath {
self.tableView.deleteRows(at: [deleteIndexPath], with: UITableViewRowAnimation.fade)
}
case NSFetchedResultsChangeType.update:
//note that for update we update the row at _indexPath_
if indexPath != nil {
// let cell = self.tableView.cellForRowAtIndexPath(updateIndexPath)
// let supplier = fetchedResultsController.objectAtIndexPath(updateIndexPath)
// cell!.textLabel?.text = supplier.name
}
case NSFetchedResultsChangeType.move:
//note that for Move we delete the row at _indexPath_
if let deleteIndexPath = indexPath {
self.tableView.insertRows(at: [deleteIndexPath], with: UITableViewRowAnimation.fade)
}
//note that for move we insert a row at _newIndexPath_
if let insertIndexPath = newIndexPath {
self.tableView.insertRows(at: [insertIndexPath], with: UITableViewRowAnimation.fade)
}
}
}
如果有帮助,请在self.tableView.insertRows(at: [insertIndexPath], with: UITableViewRowAnimation.fade)
行上。无法在任何地方找到明确的日志。
更新2:在控制台中断时键入bt会产生以下结果:
(lldb) bt
* thread #1, queue = 'NSManagedObjectContext 0x6040003cb8b0', stop reason = breakpoint 1.2
frame #0: 0x000000010c8e3b86 libc++abi.dylib`__cxa_throw
frame #1: 0x0000000106ee2068 libobjc.A.dylib`objc_exception_throw + 343
frame #2: 0x0000000107ff8362 CoreFoundation`+[NSException raise:format:arguments:] + 98
frame #3: 0x0000000106986089 Foundation`-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
frame #4: 0x00000001096d9430 UIKit`-[UITableView _endCellAnimationsWithContext:] + 18124
frame #5: 0x00000001096f5524 UIKit`-[UITableView _updateRowsAtIndexPaths:withUpdateAction:rowAnimation:usingPresentationValues:] + 1342
frame #6: 0x00000001096f55f7 UIKit`-[UITableView insertRowsAtIndexPaths:withRowAnimation:] + 118
* frame #7: 0x00000001062013fd SC Dev`StockModel.controller(controller=0x00006000000efe00, anObject=Any @ 0x00007fff59ae7458, indexPath=nil, type=insert, newIndexPath=2 indices, self=0x0000600000478940) at StockModel.swift:283
frame #8: 0x0000000106201f30 SC Dev`@objc StockModel.controller(_:didChange:at:for:newIndexPath:) at StockModel.swift:0
frame #9: 0x0000000107b6ef17 CoreData`__82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 5767
frame #10: 0x0000000107a13bf8 CoreData`developerSubmittedBlockToNSManagedObjectContextPerform + 168
frame #11: 0x000000010cccb43c libdispatch.dylib`_dispatch_client_callout + 8
frame #12: 0x000000010ccd2338 libdispatch.dylib`_dispatch_queue_barrier_sync_invoke_and_complete + 392
frame #13: 0x0000000107a13afe CoreData`-[NSManagedObjectContext performBlockAndWait:] + 286
frame #14: 0x0000000107b6d877 CoreData`-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
frame #15: 0x0000000107f8f07c CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
frame #16: 0x0000000107f8ef7a CoreFoundation`_CFXRegistrationPost + 442
frame #17: 0x0000000107f8ecc2 CoreFoundation`___CFXNotificationPost_block_invoke + 50
frame #18: 0x0000000107f50a32 CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826
frame #19: 0x0000000107f4fbac CoreFoundation`_CFXNotificationPost + 652
frame #20: 0x00000001068c3842 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 66
frame #21: 0x00000001079fcbd5 CoreData`-[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 773
frame #22: 0x0000000107a9e0ca CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1658
frame #23: 0x00000001079f6f0f CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2399
frame #24: 0x00000001079fa7d3 CoreData`-[NSManagedObjectContext save:] + 419
frame #25: 0x00000001062032fc SC Dev`StockModel.doSaveContext(self=0x0000600000673000) at StockModel.swift:381
frame #26: 0x000000010620affd SC Dev`StockModel.savePurchaseOrderWith(poId="", supplier=nil, issueDate=2018-02-06 21:17:37 UTC, deliveryDate=2018-02-06 21:17:37 UTC, deliveryStatus=false, self=0x0000600000673000) at StockModel.swift:592
frame #27: 0x000000010626ce76 SC Dev`PurchaseOrderDetailViewController.viewDidLoad(self=0x00007f941e038800) at PurchaseOrderDetailViewController.swift:68
frame #28: 0x0000000106270f84 SC Dev`@objc PurchaseOrderDetailViewController.viewDidLoad() at PurchaseOrderDetailViewController.swift:0
frame #29: 0x000000010975ad51 UIKit`-[UIViewController loadViewIfRequired] + 1235
frame #30: 0x00000001097a24dc UIKit`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
frame #31: 0x00000001097a2818 UIKit`-[UINavigationController _startTransition:fromViewController:toViewController:] + 153
frame #32: 0x00000001097a392f UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 841
frame #33: 0x00000001097a4b90 UIKit`-[UINavigationController __viewWillLayoutSubviews] + 115
frame #34: 0x00000001099fb2ae UIKit`-[UILayoutContainerView layoutSubviews] + 231
frame #35: 0x000000010968b551 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1331
frame #36: 0x00000001093fb4ba QuartzCore`-[CALayer layoutSublayers] + 153
frame #37: 0x00000001093ff5a9 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 401
frame #38: 0x00000001093881cd QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 365
frame #39: 0x00000001093b3ae4 QuartzCore`CA::Transaction::commit() + 500
frame #40: 0x00000001095e7687 UIKit`_afterCACommitHandler + 272
frame #41: 0x0000000107f95db7 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
frame #42: 0x0000000107f95d0e CoreFoundation`__CFRunLoopDoObservers + 430
frame #43: 0x0000000107f7a324 CoreFoundation`__CFRunLoopRun + 1572
frame #44: 0x0000000107f79a89 CoreFoundation`CFRunLoopRunSpecific + 409
frame #45: 0x000000010f6de9c6 GraphicsServices`GSEventRunModal + 62
frame #46: 0x00000001095bcd30 UIKit`UIApplicationMain + 159
frame #47: 0x0000000106142607 SC Dev`main at AppDelegate.swift:18
frame #48: 0x000000010cd47d81 libdyld.dylib`start + 1
更新3:将_ = doSaveContext()
包裹在DispatchQueue.main.async {
中让我向前走了几步,但仍然像以前一样在下面的日志中打破了同一个表插入行。
bt
* thread #1, queue = 'NSManagedObjectContext 0x6000001da400', stop reason = breakpoint 1.1
frame #0: 0x000000010945bf11 libobjc.A.dylib`objc_exception_throw
frame #1: 0x000000010a572362 CoreFoundation`+[NSException raise:format:arguments:] + 98
frame #2: 0x0000000108f00089 Foundation`-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
frame #3: 0x000000010b9e0430 UIKit`-[UITableView _endCellAnimationsWithContext:] + 18124
frame #4: 0x000000010b9fc524 UIKit`-[UITableView _updateRowsAtIndexPaths:withUpdateAction:rowAnimation:usingPresentationValues:] + 1342
frame #5: 0x000000010b9fc5f7 UIKit`-[UITableView insertRowsAtIndexPaths:withRowAnimation:] + 118
* frame #6: 0x000000010877a0cd SC Dev`StockModel.controller(controller=0x00006000000fea00, anObject=Any @ 0x00007fff575731c8, indexPath=nil, type=insert, newIndexPath=2 indices, self=0x000060400046aa00) at StockModel.swift:283
frame #7: 0x000000010877ac00 SC Dev`@objc StockModel.controller(_:didChange:at:for:newIndexPath:) at StockModel.swift:0
frame #8: 0x000000010a0e8f17 CoreData`__82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 5767
frame #9: 0x0000000109f8dbf8 CoreData`developerSubmittedBlockToNSManagedObjectContextPerform + 168
frame #10: 0x000000010f23843c libdispatch.dylib`_dispatch_client_callout + 8
frame #11: 0x000000010f23f338 libdispatch.dylib`_dispatch_queue_barrier_sync_invoke_and_complete + 392
frame #12: 0x0000000109f8dafe CoreData`-[NSManagedObjectContext performBlockAndWait:] + 286
frame #13: 0x000000010a0e7877 CoreData`-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
frame #14: 0x000000010a50907c CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
frame #15: 0x000000010a508f7a CoreFoundation`_CFXRegistrationPost + 442
frame #16: 0x000000010a508cc2 CoreFoundation`___CFXNotificationPost_block_invoke + 50
frame #17: 0x000000010a4caa32 CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826
frame #18: 0x000000010a4c9bac CoreFoundation`_CFXNotificationPost + 652
frame #19: 0x0000000108e3d842 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 66
frame #20: 0x0000000109f76bd5 CoreData`-[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 773
frame #21: 0x000000010a0180ca CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1658
frame #22: 0x0000000109f70f0f CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2399
frame #23: 0x0000000109f747d3 CoreData`-[NSManagedObjectContext save:] + 419
frame #24: 0x000000010877bfcc SC Dev`StockModel.doSaveContext(self=0x000060000046fec0) at StockModel.swift:381
frame #25: 0x0000000108783ebe SC Dev`closure #1 in StockModel.savePurchaseOrderWith(self=0x000060000046fec0) at StockModel.swift:593
frame #26: 0x0000000108783f52 SC Dev`partial apply for closure #1 in StockModel.savePurchaseOrderWith(_:supplier:issueDate:deliveryDate:deliveryStatus:) at StockModel.swift:0
frame #27: 0x00000001086c0b89 SC Dev`thunk for @callee_owned () -> () at AddProductViewController.swift:0
frame #28: 0x000000010f2373f7 libdispatch.dylib`_dispatch_call_block_and_release + 12
frame #29: 0x000000010f23843c libdispatch.dylib`_dispatch_client_callout + 8
frame #30: 0x000000010f2436f0 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 628
frame #31: 0x000000010a52fef9 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
frame #32: 0x000000010a4f4662 CoreFoundation`__CFRunLoopRun + 2402
frame #33: 0x000000010a4f3a89 CoreFoundation`CFRunLoopRunSpecific + 409
frame #34: 0x0000000111c579c6 GraphicsServices`GSEventRunModal + 62
frame #35: 0x000000010b8c3d30 UIKit`UIApplicationMain + 159
frame #36: 0x00000001086bb2d7 SC Dev`main at AppDelegate.swift:18
frame #37: 0x000000010f2b4d81 libdyld.dylib`start + 1
(lldb)
答案 0 :(得分:1)
无法确定,但您的堆栈跟踪强烈暗示该问题与从NSFetchedResultsControllerDelegate
回调更新表视图有关。从您的一条评论中,最有可能的原因是您没有在任何地方的表格视图中调用beginUpdates()
。
从NSFetchedResultsControllerDelegate
更新表格视图有两种基本方法。首先,简单但不是最佳:不要实施controllerWillChangeContent(_:)
或controller(_:didChange:at:for:newIndexPath:)
。 执行实施controllerDidChangeContent(_:)
,但在表格视图中使用该方法reloadData()
。不要打扰开始/结束更新或插入/删除/ etc行。
第二个,更好但稍微复杂一点的是所有这些:
controllerWillChangeContent(_:)
并使用它来致电beginUpdates()
。controller(_:didChange:at:for:newIndexPath:)
以在表格中插入/更新/等行。controllerDidChangeContent(_:)
并使用它来致电endUpdates()
。“开始”和“结束”通话都至关重要。我无法100%确定这是导致您特定崩溃的原因,但我希望不让beginUpdates()
导致某种崩溃。