本文介绍了无法创建externalDataReference临时文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我在我的iOS项目中使用Core Data。
我使用多个上下文以下列方式。我有一个 persisent商店上下文
,它对私有队列进行操作,并存储对持久存储的更改。
一个主队列上下文
,它是持久存储上下文
的子节点。所有的 FRC
在我的应用程序使用这个上下文。
最后,如果我要做一些更改我想要批量保存,我创建并使用新的 NSManagedObjectContext
s作为主队列上下文的子级。
所以我有一个链:
DB<持久存储上下文主队列上下文任何其他子上下文
我有一个单例,保留 / code>和主队列上下文
。这个singleton也监听持久化存储上下文
上的 NSManagedObjectContextObjectsDidChangeNotification
通知,如下所示:
- (void)persistentStoreContextDidChangeNotification:(NSNotification *)notification
{
if(notification.object == self.persistentStoreContext) {
[self.persistentStoreContext performBlockAndWait:^ {
//对persistentStoreContext的每个更改,使用后台线程保存这些更改到真正的持久存储
NSError * error = nil;
[self.persistentStoreContext save:& error];
}];
}
}
[mainQueueContext save]
,这足以使 mainQueueContext
中的所有更改都保留在文件系统中。
使用Crashlytics,我得到了很多崩溃报告,像这样:
致命异常:NSInternalInconsistencyException
无法创建externalDataReference临时文件:28
线程:致命异常: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:错误:] + 720
6 CoreData 0x0000000183cd2254 __65- [NSPersistentStoreCoordinator executeRequest:withContext:错误:] _ 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:错误:] + 300
12 CoreData 0x0000000183c31400 - [保存的NSManagedObjectContext:] + 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分配基金会0x0000000184d32cc0 - [NSNotificationCenter postNotificationName:对象:用户信息:] + 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的:错误:] + 1568
23 CoreData 0x0000000183cae684 __82- [的NSManagedObjectContext(_NestedContextSupport)executeRequest:withContext:错误: ] _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基础0x0000000184e07508 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
33基础0x0000000184d58c94 - [NSBlockOperation main] + 96
34基础0x0000000184d4861c - [__ NSOperationInternal _start:] + 636
35基础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]
从应用程序的不同部分调用的情况下。
我想知道我为什么会看到这个异常的可能原因。我在搜索无法创建externalDataReference临时文件时在Google上找不到任何内容
p>
我已经经历了特定的崩溃实例,一个一个地看着他们。虽然每个崩溃的堆栈跟踪是相当类似的,但事实证明,异常在实例之间有一点不同。
这个崩溃的不同版本是:
致命异常:NSInternalInconsistencyException
外部数据引用无法找到基础文件。
,
致命异常:NSInternalInconsistencyException
路径/文件中丢失的字节/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
,
致命异常:NSInvalidArgumentException
无法打开带有路径的文件:/ var / mobile / Containers / Data / Application /19E53BC4-7891-4B0C-9454-27C1A0DAB2A0/Documents/persistent-store/.Model_SUPPORT/_EXTERNAL_DATA/CA6BCE7D-0C74-41CF-8784-8EB1F66DFF4C(13)
,
致命异常:NSInternalInconsistencyException
此NSPersistentStoreCoordinator持久存储。它不能执行保存操作。
此外,我发现了几乎所有这种类型的崩溃共享的模式。
设备上的可用磁盘空间非常低。在iPhone 4和iPhone 5设备上,可用磁盘空间为0%。在iPhone 6上,它总是8%。
我怀疑iPhone 6在特殊场合保留8%的磁盘空间。
$ b $我在我的应用程序中使用类似的过程,在构建我的核心数据栈期间设置了两个上下文,并使用:
-
NSPrivateQueueConcurrencyType
,
-
NSMainQueueConcurrencyType
。
要猜测,这些块可能与通知的操作冲突,
对于我的应用程序,我修改了Marcus Zarra在他的书The Pragmatic Bookshelf - Core Data,2nd Edition,Data Storage and Management for iOS ,OS X和iCloud(2013年1月)。
有关更多最新和所有尚未实现的解决方案,请阅读这篇文章。
我修改的解决方案涉及编写一个与我的核心数据堆栈(在同一个类中)构建的自定义保存方法,如下所示,而不是使用 NSManagedObjectContextObjectsDidChangeNotification
。请注意,保存方法在代码中的适当点调用。
也许这是一个合适的选择吗?
属性...
@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成功;
if(!(success = [self.mocMain save:& error]))
NSLog(@%@ - %@ - CORE DATA - E〜R〜R〜O〜R saved managedObjectContext MAIN:%@,%@,NSStringFromClass(self.class),NSStringFromSelector(_cmd),error.localizedDescription,error.localizedFailureReason);
NSLog(@%@ - %@ - CORE DATA - 成功保存managedObjectContext MAIN ?:%@,NSStringFromClass(self.class),NSStringFromSelector(_cmd),success?@YES_:@NO_ );
}];
}
void(^ savePrivate)(void)= ^ {
NSError __autoreleasing * error;
BOOL成功;
if(!(success = [self.mocPrivate save:& error]))
NSLog(@%@ - %@ - CORE DATA - E〜R〜R〜O〜R saved managedObjectContext PRIVATE:%@,%@,NSStringFromClass(self.class),NSStringFromSelector(_cmd),error.localizedDescription,error.localizedFailureReason);
NSLog(@%@ - %@ - CORE DATA - 成功保存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];
}
}
}
I use Core Data in my iOS project.
I am using multiple contexts in the following way. I have a persisent store context
that operates on a private queue and stores changes to the persistent store.
I have a main queue context
that is the child of persistent store context
. All of the FRC
s in my app use this context.
And finally, if I have to do some changes that I want to save in a batch, I create and use new NSManagedObjectContext
s that are children of the main queue context.
So I have a chain:
DB < persistent store context < main queue context < any other child contexts
I have a singleton that retains both persistent store context
and main queue context
. This singleton also listens to NSManagedObjectContextObjectsDidChangeNotification
notification on persistent store context
and reacts to the notification like this:
-(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];
}];
}
}
So, when I call [mainQueueContext save]
, this is enough for all changes in mainQueueContext
to be persisted in the filesystem.
Using Crashlytics, I am getting a lot of crash reports like this:
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
So, in this specific crash, the line
30 MyApp 0x000000010012ea14 __78-[MyAppManager downloadMediaIfNeededForMyAppWithManagedObjectID:onCompletion:]_block_invoke (MyAppManager.m:415)
is calling [mainQueueContext save]
.The same crash occurs in situations where the [mainQueueContext save]
is called from different parts of the app.
I am trying to find out what are the possible reasons why I am seeing this exception. And I cannot find anything on Google when searching for "Can't create externalDataReference interim file"
EDIT
I have went through specific crash instances and looked at them one by one. Although the stack trace of every crash is fairly similar, it turns out that the exception differs a little bit between instances.
The differents 'versions' of this crash are:
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.
Also, I have discovered a pattern shared by almost all the crashes of this type.The available disk space on the device is extremely low. On iPhone 4 and iPhone 5 devices the available disk space is 0%. And on iPhone 6, it's always 8%.
I suspect that the iPhone 6 reserves 8% of disk space "for special occasions".
解决方案
I use a similar process in my app, with two contexts set during the construction of my core data stack and using:
NSPrivateQueueConcurrencyType
, NSMainQueueConcurrencyType
.
To take a guess, the blocks may be conflicting with the operation of the notification, however that is a guess.
For my app I've modified the solution presented by Marcus Zarra in his book from The Pragmatic Bookshelf – "Core Data, 2nd Edition, Data Storage and Management for iOS, OS X, and iCloud" (Jan 2013).
For a more up to date and all encompassing solution that I have not yet implemented, read this article My Core Data Stack by Zarra.
My modified solution involves writing a custom save method built alongside (in the same class as) my core data stack, shown following, instead of using a NSManagedObjectContextObjectsDidChangeNotification
. Note that the save method is called at appropriate points in code.
Maybe this is a suitable alternative?
Properties...
@property (nonatomic, strong) NSManagedObjectContext *mocPrivate;
@property (nonatomic, strong) NSManagedObjectContext *mocMain;
Custom save method...
- (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];
}
}
}
这篇关于无法创建externalDataReference临时文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!