CoreData保存崩溃:NSInvalidArgumentException异常排查求助
CoreData保存/更新时崩溃:NSInvalidArgumentException异常
崩溃场景
对CoreData中的记录执行保存或更新操作时,应用崩溃,抛出NSInvalidArgumentException异常,错误信息为:
-[NSConcreteHashTable values]: unrecognized selector sent to instance
崩溃详情
Fatal Exception: NSInvalidArgumentException 0 CoreFoundation 0x9e48 __exceptionPreprocess 1 libobjc.A.dylib 0x178d8 objc_exception_throw 2 CoreFoundation 0x17e82c +[NSObject(NSObject) _copyDescription] 3 CoreFoundation 0x1ff60 ___forwarding___ 4 CoreFoundation 0x88330 _CF_forwarding_prep_0 5 CoreData 0x323ec -[NSSQLSavePlan _recordToManyChangesForObject:inRow:usingTimestamp:inserted:] 6 CoreData 0x40a3c -[NSSQLSavePlan _createRowsForSave] 7 CoreData 0xe87ac -[NSSQLSavePlan prepareRows] 8 CoreData 0x1b2e0 -[NSSQLSaveChangesRequestContext executePrologue] 9 CoreData 0x1b00c -[NSSQLCore dispatchRequest:withRetries:] 10 CoreData 0x26500 -[NSSQLCore executeRequest:withContext:error:] 11 CoreData 0x199078 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke.551 12 CoreData 0x61608 -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] 13 CoreData 0x25644 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] 14 CoreData 0x8d15c -[NSManagedObjectContext save:] 15 0x2d30c DataController.updateRecord(_:object:) + 193 (DataController.swift:193) 16 0x2e6ec DataController.removeAllLocalUrl() + 322 (DataController.swift:322) 17 0x7f5a0 specialized closure #1 in AppDelegate.getUserInfoCallBack(_:email:completion:) + 643 (AppDelegate.swift:643) 18 0x8d2a0 partial apply for closure #1 in AppDelegate.getUserInfoCallBack(_:email:completion:) (<compiler-generated>) 19 0x8b9c8 partial apply for closure #1 in RestApiManager.makeHTTPPostRequest(_:jsonBody:onCompletion:) (<compiler-generated>) 20 0x82350 thunk for @escaping @callee_guaranteed @Sendable (@guaranteed Data?, @guaranteed NSURLResponse?, @guaranteed Error?) -> () (<compiler-generated>) 21 CFNetwork 0x208d4 CFURLRequestSetMainDocumentURL 22 CFNetwork 0x30958 _CFNetworkErrorCopyLocalizedDescriptionWithHostname 23 libdispatch.dylib 0x24b4 _dispatch_call_block_and_release 24 libdispatch.dylib 0x3fdc _dispatch_client_callout 25 libdispatch.dylib 0xb694 _dispatch_lane_serial_drain 26 libdispatch.dylib 0xc214 _dispatch_lane_invoke 27 libdispatch.dylib 0x16e10 _dispatch_workloop_worker_thread 28 libsystem_pthread.dylib 0xdf8 _pthread_wqthread 29 libsystem_pthread.dylib 0xb98 start_wqthread com.apple.main-thread 0 libsystem_kernel.dylib 0x4aa8 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x16fc4 mach_msg2_internal + 80 2 libsystem_kernel.dylib 0x17204 mach_msg_overwrite + 388 3 libsystem_kernel.dylib 0x4fec mach_msg + 24 4 CoreFoundation 0x7aad4 __CFRunLoopServiceMachPort + 160 5 CoreFoundation 0x7bd18 __CFRunLoopRun + 1232 6 CoreFoundation 0x80ec0 CFRunLoopRunSpecific + 612 7 GraphicsServices 0x1368 GSEventRunModal + 164 8 UIKitCore 0x3a186c -[UIApplication _run] + 888 9 UIKitCore 0x3a14d0 UIApplicationMain + 340 10 0x14100 main + 47 (AppDelegate.swift:47) 11 ??? 0x1c9312960 (Missing)
相关代码
if object.localUrl != nil { record.setValue(object.localUrl, forKey: "localUrl") }else{ record.setValue("", forKey: "localUrl") } if object.transcribe != nil { record.setValue(object.transcribe, forKey: "transcribe") }else{ record.setValue("", forKey: "transcribe") } do { try record.managedObjectContext?.save() // **193 This is the Crash Line** } catch { let saveError = error as NSError Functions.log(saveError.localizedDescription) Crashlytics.crashlytics().setCustomValue(saveError.localizedDescription, forKey: "saveError") }
问题分析与修复方案
核心原因
崩溃栈指向CoreData处理一对多关联(to-many)时出错,说明某个关联属性的类型不符合CoreData要求,或多线程操作违规导致对象状态异常。
具体修复步骤
检查CoreData模型的关联关系类型
打开你的.xcdatamodeld文件,查看所有一对多关联的属性:- Swift环境下,关联属性必须是
Set<关联对象类型> - Objective-C环境下,必须是
NSSet或NSOrderedSet
禁止使用NSHashTable(即崩溃中的NSConcreteHashTable)作为关联集合类型,CoreData无法识别这种类型的关联变更。
- Swift环境下,关联属性必须是
规范多线程CoreData操作
从崩溃栈看,保存操作在后台线程执行,需确保:- 每个线程使用独立的
NSManagedObjectContext,推荐用privateQueueConcurrencyType - 所有修改、保存操作都通过
perform/performAndWait提交到Context的队列,避免跨线程访问对象:let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) privateContext.parent = mainContext privateContext.perform { // 执行对象修改操作 do { try privateContext.save() // 同步到主上下文 mainContext.perform { try? mainContext.save() } } catch { // 处理错误 } }
- 每个线程使用独立的
修正属性赋值逻辑
检查localUrl和transcribe的CoreData模型类型:- 如果模型中是
URL类型,不能赋值空字符串,应该传nil:record.setValue(object.localUrl, forKey: "localUrl") // 无需手动替换为空字符串,CoreData会自动处理nil值 - 确保赋值的类型和模型定义完全匹配,比如字符串类型不能传URL实例,反之亦然。
- 如果模型中是
重置异常对象状态
如果某个Managed Object的关联集合被意外污染成NSHashTable,可以尝试重置对象状态:record.managedObjectContext?.refresh(record, mergeChanges: false)
内容的提问来源于stack exchange,提问作者Sunny Shah
相关产品推荐
相关产品推荐

