2010-01-05 41 views
28

我正在做一个iPhone应用程序,它从XML文件读取数据,将它们转换为核心数据管理对象并保存它们。核心数据的隐藏错误:NSInvalidArgumentException,原因:referenceData64只为抽象类定义

该应用程序工作正常,主要是在较小的数据集/ XML包含〜150个对象。我说的时候,主要是因为10%,我会从CoreData出现以下情况例外,当设法保存上下文:

*终止应用程序由于未捕获的异常“NSInvalidArgumentException”,原因是:“* -_referenceData64只为抽象类定义。定义 - [NSTemporaryObjectID_default _referenceData64]!'

对于一个更大的数据集(〜2000),这种情况每次都会发生,但不在同一个地方。它可能会在第137条记录中,第580条或最后一条记录上失败。我试着移动保存点(每个对象,每10个对象,保存一次所有对象都被分配/初始化),但我总是遇到上述异常。

我google了异常,看到有人有同样的问题,但没有看到任何决议。

我的下一步就是将管理对象和关系简化为一个点,在这个点上这个错误停止并从那里建立以隔离问题。最后的手段是沟渠核心数据,并直接存储到sqllite。

感谢您的帮助!

+0

您是否在模型中使用任何抽象实体? – 2010-01-06 03:01:03

+0

嗨马库斯,我没有使用抽象的实体,但我使用多个线程,我没有意识到在线程中使用核心数据的规则。 – Brombie 2010-01-09 10:47:08

+0

我不完全确定,但在我看来,你有一个抽象的实体,你试图实例化。你能指导我们继承吗? 多么奇怪的错误信息! – beinstein 2011-02-17 12:06:37

回答

27

我有同样的问题。它适用于较小的数据集,但对于较大的集合,我会得到“仅为抽象类定义的_referenceData64”错误。我的模型中没有抽象实体。

编辑:

我想我得到了这个解决。在我的情况下,这个问题在我的部分re线程上出现混乱。以下是我遵循的修复方法:

  1. 我在一个线程中解析XML数据。在启动所述线程时,使用与主线程的NSManagedObjectContext相同的持久存储协调器创建一个新的NSManagedObjectContext。
  2. 您在线程中创建的任何新对象都应该针对线程的NSManagedObjectContext进行创建。如果您必须复制主线程的NSManagedObjectContext中的对象,请按ID复制。即
    NSManagedObjectID *objectID = [foo objectID];
    FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] retain]
  3. 完成解析后,您需要保存对线程的NSManagedObjectContext所做的更改。您必须锁定持久性商店协调员。我用下面的(不完整的代码):

`

- (void)onFinishParsing { 
    // lock the store we share with main thread's context 
    [persistentStoreCoordinator lock]; 

    // save any changes, observe it so we can trigger merge with the actual context 
    @try { 
    [threadManagedObjectContext processPendingChanges]; 
    } 
    @catch (NSException * e) { 
    DLog(@"%@", [e description]); 
    [persistentStoreCoordinator unlock]; 
    } 
    @finally { 
    // pass 
    } 

    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; 
    [dnc addObserver:self selector:@selector(threadControllerContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:threadManagedObjectContext]; 
    @try { 
    NSError *error; 
    if (![threadManagedObjectContext save:&error]) { 
     DLog(@"%@", [error localizedDescription]); 
     [persistentStoreCoordinator unlock]; 
     [self performSelectorOnMainThread:@selector(handleSaveError:) withObject:nil waitUntilDone:NO]; 
    } 
    } @catch (NSException *e) { 
    DLog(@"%@", [e description]); 
    [persistentStoreCoordinator unlock]; 
    } @finally { 
    // pass 
    } 
    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:threadManagedObjectContext]; 

    [self performSelectorOnMainThread:@selector(parserFinished:) withObject:nil waitUntilDone:NO]; 
} 

// Merging changes causes the fetched results controller to update its results 
- (void)threadControllerContextDidSave:(NSNotification*)saveNotification { 
    // need to unlock before we let main thread merge 
    [persistentStoreCoordinator unlock]; 
    [self performSelectorOnMainThread:@selector(mergeToMainContext:) withObject:saveNotification waitUntilDone:YES]; 
} 

- (void)mergeToMainContext:(NSNotification*)saveNotification { 
    NSError *error; 
    [managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; 
    if (![managedObjectContext save:&error]) { 
    DLog(@"%@", [error localizedDescription]); 
    [self handleSaveError:nil]; 
    } 
} 

`

+0

这是一个很好的回应,但请注意这个线程:http://stackoverflow.com/questions/3446983/collection-was-mutated-while-being-enumerated-on-executefetchrequest它解释了threadManagedObjectContext必须被创建在新线程内。 – gonso 2011-03-01 10:59:21

+0

Swift 2+有更好的方式来管理并发MOC。我发现这个教程相当有用https://www.cocoanetics.com/2012/07/multi-context-coredata/ – Neilc 2016-09-09 16:28:36

1

对不起我的英语(我是法国人)。 我确实有同样的问题,我意识到我从第二个线程调用Core Data Framework上的一个方法(插入一个对象)。我只是使用performSelectorOnMainThread从主线程调用此方法,它解决了我的问题。 我希望它能帮助你。

+0

这也解决了我的问题:)StéphaneGarzino – Bhat 2016-09-19 15:04:40

2

谢谢大家,我能够通过遵循你的提示摆脱讨厌的例外。

这是线程问题,似乎导致异常。在我的情况下,我有主线程产生工作线程来获取XML,解析,创建必要的托管对象并保存它们。

我尝试了一种懒惰的方式通过使用performSelectorOnMainThread进行保存,但没有奏效。

我最后的做法是用自己的ManagedObjectContext创建一个名为ThreadDataService的类,每个线程都有一个ThreadDataService实例,基本上Adriaan曾经提出过。

再次感谢所有的答案。你们好棒!

1

我有同样的问题,当我搜索答案时,我发现这一点。我的问题是,我开始在同一个托管上下文上工作的2个线程在保存到持久存储时崩溃 - 如果每个线程都有自己的上下文,则不会出现问题。但它可能只是通过锁定持久性存储来解决,但我相信2个托管上下文是正确的解决方案。

问候

11

你必须遵循以下规则:

的NSManagedObjectContext必须在同一线程上创建它使用 它。 (或者换句话说,每一个线程必须有自己的MOC)

违反以上规则而导致以下异常:

  • 异常的*** -_referenceData64只为抽象类定义。定义 - [NSTemporaryObjectID_default _referenceData64]!

另一个问题有人可能面对的是,如果使用的是NSFetchedResultsController,代表们将不能在UI类调用。

我希望这个答案能帮助别人!

+0

我得到这个崩溃时使用“NSFetchedResultsController,代表不会被调用的UI类。“..我该怎么办? – 2016-05-11 10:55:31

2

在下面的块中做nsmanagedobject数据和managedobjectcontext的保存映射,以便锁定managedobjectcontext不被另一个线程访问并解决崩溃。

[context performBlockAndWait:^{ 

    //your code 
    [context save:&error]; 

}]; 
+0

NSInvalidArgumentException',原因:'只能在使用队列创建的NSManagedObjectContext上使用-performBlockAndWait: – 2018-01-31 06:01:45

相关问题