无法创buildexternalDataReference临时文件

我在我的iOS项目中使用核心数据。

我以下面的方式使用多个上下文。 我有一个persisent store context ,在一个私有队列上运行,并将更改存储在持久存储中。

我有一个main queue contextpersistent store context的孩子。 我的应用程序中的所有FRC使用此上下文。

最后,如果我必须做一些我希望在批处理中保存的更改,我创build并使用作为主队列上下文的子项的新NSManagedObjectContext

所以我有一个链:

 DB < persistent store context < main queue context < any other child contexts 

我有一个保留persistent store contextmain queue context的单例。 这个单例还会监听persistent store context NSManagedObjectContextObjectsDidChangeNotification通知,并对通知作出如下反应:

 -(void) persistentStoreContextDidChangeNotification:(NSNotification*)notification { if (notification.object == self.persistentStoreContext) { [self.persistentStoreContext performBlockAndWait:^{ //on every change on persistentStoreContext, save those changes using background thread to real persistent store NSError *error = nil; [self.persistentStoreContext save:&error]; }]; } } 

所以,当我调用[mainQueueContext save] ,这足以让mainQueueContext所有更改mainQueueContext在文件系统中。

使用Crashlytics,我得到了很多像这样的崩溃报告:

 Fatal Exception: NSInternalInconsistencyException Can't create externalDataReference interim file : 28 Thread : Fatal Exception: NSInternalInconsistencyException 0 CoreFoundation 0x0000000183f51e48 __exceptionPreprocess + 132 1 libobjc.A.dylib 0x000000019464c0e4 objc_exception_throw + 60 2 CoreData 0x0000000183c6e5b4 +[_PFRoutines writePFExternalReferenceDataToInterimFile:] + 960 3 CoreData 0x0000000183ceaa4c -[NSSQLCore writeExternalDataReferences] + 224 4 CoreData 0x0000000183c429fc -[NSSQLCore saveChanges:] + 596 5 CoreData 0x0000000183c0b078 -[NSSQLCore executeRequest:withContext:error:] + 720 6 CoreData 0x0000000183cd2254 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 4052 7 CoreData 0x0000000183cd9654 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 180 8 libdispatch.dylib 0x0000000194c9136c _dispatch_client_callout + 16 9 libdispatch.dylib 0x0000000194c9a6e8 _dispatch_barrier_sync_f_invoke + 76 10 CoreData 0x0000000183ccccb4 _perform + 180 11 CoreData 0x0000000183c0ac34 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 300 12 CoreData 0x0000000183c31400 -[NSManagedObjectContext save:] + 1284 13 MyApp 0x00000001000d17e0 __58-[XEECDStack persistentStoreContextDidChangeNotification:]_block_invoke (XEECDStack.m:426) 14 CoreData 0x0000000183ca5270 developerSubmittedBlockToNSManagedObjectContextPerform + 200 15 CoreData 0x0000000183ca5474 -[NSManagedObjectContext performBlockAndWait:] + 232 16 MyApp 0x00000001000d1774 -[XEECDStack persistentStoreContextDidChangeNotification:] (XEECDStack.m:423) 17 CoreFoundation 0x0000000183ef81e0 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20 18 CoreFoundation 0x0000000183e37370 _CFXNotificationPost + 2060 19 Foundation 0x0000000184d32cc0 -[NSNotificationCenter postNotificationName:object:userInfo:] + 72 20 CoreData 0x0000000183c33d14 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 364 21 CoreData 0x0000000183c321bc -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2552 22 CoreData 0x0000000183cadba4 -[NSManagedObjectContext(_NestedContextSupport) _parentProcessSaveRequest:inContext:error:] + 1568 23 CoreData 0x0000000183cae684 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 600 24 CoreData 0x0000000183cb0398 internalBlockToNSManagedObjectContextPerform + 108 25 libdispatch.dylib 0x0000000194c9136c _dispatch_client_callout + 16 26 libdispatch.dylib 0x0000000194c9a6e8 _dispatch_barrier_sync_f_invoke + 76 27 CoreData 0x0000000183ca06cc _perform + 208 28 CoreData 0x0000000183cae354 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] + 176 29 CoreData 0x0000000183c31400 -[NSManagedObjectContext save:] + 1284 30 MyApp 0x000000010012ea14 __78-[MyAppManager downloadMediaIfNeededForMyAppWithManagedObjectID:onCompletion:]_block_invoke (MyAppManager.m:415) 31 MyApp 0x00000001001ce06c __38-[FLNMyAppMediaDownloadOperation main]_block_invoke60 (FLNMyAppMediaDownloadOperation.m:84) 32 Foundation 0x0000000184e07508 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16 33 Foundation 0x0000000184d58c94 -[NSBlockOperation main] + 96 34 Foundation 0x0000000184d4861c -[__NSOperationInternal _start:] + 636 35 Foundation 0x0000000184e0a26c __NSOQSchedule_f + 228 36 libdispatch.dylib 0x0000000194c9136c _dispatch_client_callout + 16 37 libdispatch.dylib 0x0000000194c95980 _dispatch_main_queue_callback_4CF + 932 38 CoreFoundation 0x0000000183f096a0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 39 CoreFoundation 0x0000000183f07748 __CFRunLoopRun + 1492 40 CoreFoundation 0x0000000183e351f4 CFRunLoopRunSpecific + 396 41 GraphicsServices 0x000000018cfcb5a4 GSEventRunModal + 168 42 UIKit 0x0000000188766784 UIApplicationMain + 1488 43 MyApp 0x0000000100119cc8 main (main.m:17) 44 libdyld.dylib 0x0000000194cbaa08 start + 4 

所以,在这个具体的崩溃,行

 30 MyApp 0x000000010012ea14 __78-[MyAppManager downloadMediaIfNeededForMyAppWithManagedObjectID:onCompletion:]_block_invoke (MyAppManager.m:415) 

正在调用[mainQueueContext save] 。 在从应用程序的不同部分调用[mainQueueContext save]情况下会发生同样的崩溃。

我试图找出为什么我看到这个例外的可能原因。 在search"Can't create externalDataReference interim file"时,我无法在Google上find任何内容

编辑

我已经经历了特定的崩溃事件,并逐个看着他们。 尽pipe每次崩溃的堆栈跟踪都非常相似,但实例之间的exception情况稍有不同。

这个崩溃的不同版本是:

 Fatal Exception: NSInternalInconsistencyException External data reference can't find underlying file. 

 Fatal Exception: NSInternalInconsistencyException Missing bytes from file at path /private/var/mobile/Containers/Data/Application/E9D51467-7941-41B8-88EE-31A70A82BC40/tmp/.LINKS/BD171390-D95C-459E-96D6-462318016138/EDB75A4F-C8FD-4BC4-ABD1-BA408F3A7DC9_0x18038c80, expected 276428, got 4294967295 

 Fatal Exception: NSInvalidArgumentException Unable to open file with path: /var/mobile/Containers/Data/Application/19E53BC4-7891-4B0C-9454-27C1A0DAB2A0/Documents/persistent-store/.Model_SUPPORT/_EXTERNAL_DATA/CA6BCE7D-0C74-41CF-8784-8EB1F66DFF4C (13) 

 Fatal Exception: NSInternalInconsistencyException This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation. 

另外,我发现几乎所有这种types的崩溃都有一个模式。 设备上的可用磁盘空间非常less。 在iPhone 4和iPhone 5设备上,可用磁盘空间为0%。 而在iPhone 6上,总是8%。

我怀疑iPhone 6预留8%的磁盘空间“特殊场合”。

我在我的应用程序中使用了一个类似的过程,在构build核心数据堆栈过程中设置了两个上下文,并使用:

  • NSPrivateQueueConcurrencyType
  • NSMainQueueConcurrencyType

要猜测,这些块可能与通知的操作冲突,但这是一个猜测。

对于我的应用程序,我修改了Marcus Zarra在“实用书架”(Core Data,第二版,iOS,OS X和iCloud数据存储和pipe理)(2013年1月)一书中提出的解决scheme。

有关我尚未实现的更新和全面的解决scheme,请阅读Zarra的“ 我的核心数据栈” 。

我修改后的解决scheme涉及编写一个自定义的保存方法,与我的核心数据堆栈(在同一个类中)构build,如下所示,而不是使用NSManagedObjectContextObjectsDidChangeNotification 。 请注意,保存方法在代码中的适当位置被调用。

也许这是一个合适的select?

属性…

 @property (nonatomic, strong) NSManagedObjectContext *mocPrivate; @property (nonatomic, strong) NSManagedObjectContext *mocMain; 

自定义保存方法…

 - (void)saveContextAndWait:(BOOL)wait { if ([self.mocMain hasChanges]) { [self.mocMain performBlockAndWait:^{ NSError __autoreleasing *error; BOOL success; if (!(success = [self.mocMain save:&error])) NSLog(@"%@ - %@ - CORE DATA - E~R~R~O~R saving managedObjectContext MAIN: %@, %@", NSStringFromClass(self.class), NSStringFromSelector(_cmd), error.localizedDescription, error.localizedFailureReason); NSLog(@"%@ - %@ - CORE DATA - Success saving managedObjectContext MAIN?: %@", NSStringFromClass(self.class), NSStringFromSelector(_cmd), success ? @"YES_" : @"NO_"); }]; } void (^savePrivate) (void) = ^{ NSError __autoreleasing *error; BOOL success; if (!(success = [self.mocPrivate save:&error])) NSLog(@"%@ - %@ - CORE DATA - E~R~R~O~R saving managedObjectContext PRIVATE: %@, %@", NSStringFromClass(self.class), NSStringFromSelector(_cmd), error.localizedDescription, error.localizedFailureReason); NSLog(@"%@ - %@ - CORE DATA - Success saving managedObjectContext PRIVATE?: %@", NSStringFromClass(self.class), NSStringFromSelector(_cmd), success ? @"YES_" : @"NO_"); }; if ([self.mocPrivate hasChanges]) { if (wait) { [self.mocPrivate performBlockAndWait:savePrivate]; } else { [self.mocPrivate performBlock:savePrivate]; } } } 

我已经设法通过填充设备上的整个磁盘空间,然后使用该应用程序,将媒体存储在核心数据中来重现此问题。

经过一段时间的使用应用程序,一个警告popup窗口显示设备磁盘空间不足。 我解雇了警告,并继续使用该应用程序。 经过一段时间后,该应用程序崩溃的消息:

 Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Can't create externalDataReference interim file : 28'