“核心数据不能实现故障”对于在主线程上的appDelegate managedObjectContext中创建的对象 [英] "Core Data could not fulfill a fault" for objects that were created in the appDelegate managedObjectContext on the main thread

查看:93
本文介绍了“核心数据不能实现故障”对于在主线程上的appDelegate managedObjectContext中创建的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我错误地在后台线程上创建了一组对象,创建了一个新的managedObjectContext,其中保存了对象。

I mistakenly created a group of objects on a background thread, which created a new managedObjectContext in which the objects were saved.

这导致了大量的不满足故障崩溃在我的现场应用程序。请注意 - 我不是想删除这些对象 - 这是一个问题,它们的创建方式,当我尝试在主线程上的应用程序委托(主)上下文中再次保存它们。

This resulted in numerous "Core Data could not fulfill a fault" crashes in my live app. Please note - I am not trying to delete these objects - it is a problem with the way they were created, when I try to save them again afterwards in the app delegate (main) context on the main thread.

令人困惑的事情是,我看到其他对象,不同类型的对象的此错误。它们可以与在后台线程中创建的对象相关,尽管它们本身不是在后台线程中创建的。

The thing that is confusing is that I am seeing this error for other objects, objects of a different type. They can be related to the objects created in the background thread, though they themselves were not created in the in the background thread.

我很困惑如何发生了。我如何得到一个对象没有在后台线程中创建,但应用程序委托(主)上下文中的核心数据不能完成故障错误。

I am confused as to how this could have happened. How could I get the "Core Data could not fulfill a fault" error for an object not created in the background thread, but the app delegate (main) context?

有没有什么办法可以回去并解决这个错误在我的用户的实时应用程序?

And is there any way at all to go back and fix this mistake in the live apps of my users?

让我参考我的另一个问题,我发现这个错误:
核心数据无法满足未删除对象的错误

Let me reference my other question, through which I discovered this error: "Core Data could not fulfill a fault" for objects that were not deleted

我写了一个新问题,因为我认为这是一个不同的问题 - 虽然大多数绝对相关。

I wrote up a new question because I feel that it is a different issue - though most definitely related.

这是在后台线程中创建对象的代码:

Here is the code that created the objects in the background thread:

- (void)friendPickerViewControllerDidChooseFriends:(NSArray *)friends {

    __ENTERING_METHOD__
    if (friends.count > 0) {
        [[FacebookHelper sharedManager] friendPickerController].navigationController.navigationBar.userInteractionEnabled = NO;


        [self startProgressIndicator];
        [self performSelectorInBackground:@selector(importFriends:) withObject:friends];
    }
    else {
        [self dismissModalImportViewControllerAnimated];//releases picker delegates, etc
    }
}



#pragma mark -
#pragma mark Import Friend
- (void)importFriends:(NSArray*)friends {

    __ENTERING_METHOD__
    for (NSDictionary<FBGraphUser> *friend in friends) {

        [self importFriend:friend withCompletion:^(void){

            CGFloat friendNumber = [friends indexOfObject:friend]+1;
            CGFloat friendCount = friends.count;
            self.importProgress = friendNumber/friendCount;
        }];
    }
}

- (void)importFriend:(NSDictionary<FBGraphUser>*)friend withCompletion:( void (^) (void) )completionBlock {

    __ENTERING_METHOD__
    Person *myNewPerson = [GetObjectArrayHelper createNewPersonMocSaveNew:YES];

    myNewPerson.facebookID = friend.id;
    myNewPerson.facebookName = friend.name;

    NSString *nameFirst = [friend.first_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSString *nameLast = [friend.last_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];


    NSString *imageID = friend.id;
    UIImage *pickedImage = nil;
    if(imageID){
        pickedImage = [FacebookHelper imageForObject:imageID];
    }

    DLog(@"pickedImage:%@",pickedImage);

    if(pickedImage){
        [self setImagesForFacebookImage:pickedImage forPerson:myNewPerson];
    }

    //we should ALWAYS have a name
    [Helper changePerson:myNewPerson firstName:nameFirst lastName:nameLast];

    if(completionBlock) {
        completionBlock();
    }
}


- (void)finishedImporting {

    __ENTERING_METHOD__
    [SVProgressHUD showSuccessWithStatus:[self completeString]];
    [self performSelector:@selector(dismissModalImportViewControllerAnimated) withObject:nil afterDelay:SV_PROGRESS_HUD_SUCCESS_DELAY];
}

- (void)dismissModalImportViewControllerAnimated {

    __ENTERING_METHOD__

    [Helper mocSave];//THIS SAVES IN THE APP DELEGATE MANAGED OBJECT CONTEXT -

    [SVProgressHUD dismiss];

    [self dismissViewControllerAnimated:YES completion:^(void){

        [[FacebookHelper sharedManager] friendPickerController].delegate = nil;
        [[FacebookHelper sharedManager] friendPickerController].navigationController.navigationBar.userInteractionEnabled = YES;
    }];
}



请注意,我关心的对象不是任何对象在这里创建(或在这里调用的方法),但以后与这些对象关联的对象。

Please note that the objects that I am concerned about are not any of the objects created here (or in methods called here), but objects that later become associated with these objects.

为什么他们的核心数据不能完成故障崩溃? (我明白为什么这里创建的任何对象或在这里调用的方法会得到它)。

Why are THEY "Core Data could not fulfill a fault" crash? (I understand why any object created here or in a method called here would get it).

此外 - 一旦我找出了为什么这种混乱发生导致它)我需要修复流氓对象在我的用户的实时应用程序。

Also - once I figure out why this mess happened (and fix the code that caused it) I need to fix the rogue objects in my users' live apps. I could really use some advise on that as well!

推荐答案

根据你的问题和你的意见,你是:

Based on your question and your comments, you are:


  • 在多个主题上使用单个受管理对象。

  • 不采取任何预防措施来处理 NSManagedObjectContext 不是线程安全的。

  • Using a single managed object on multiple threads.
  • Not taking any precautions to deal with the fact that NSManagedObjectContext is not thread safe.

混乱的崩溃。

这正是在这种情况下所期望的。在不使用预防措施的情况下在多个线程上使用受管对象上下文本质上是崩溃和混乱的方法。这些崩溃可能没有什么意义,因为你破坏了上下文的内部状态。

This is exactly what one would expect in this situation. Using a managed object context on more than one thread without taking precautions is essentially a recipe for crashes and confusion. These crashes may not make a lot of sense, because you're corrupting the context's internal state.

如果你想在多个线程上使用上下文,你必须使用队列限制选项之一( NSMainQueueConcurrencyType NSPrivateQueueConcurrencyType ),然后< >必须将所有使用上下文的代码或从中获取的任何对象放在 performBlock: performBlockAndWait: NSMainQueueConcurrencyType ,你知道你的代码是在主线程,你可以直接使用上下文)。你也可以使用自己的锁定机制,通过 NSLock ,但是,对于大多数人来说,线程已经足够了。

If you want to use a context on more than one thread, you must use one of the queue confinement options (NSMainQueueConcurrencyType or NSPrivateQueueConcurrencyType) and then you must put all code that uses the context or any object fetched from them in a performBlock: or performBlockAndWait:. (Exception: if you use NSMainQueueConcurrencyType and you know your code is on the main thread, you may just use the context directly). You might also use your own locking mechanism via something like NSLock, but come on, threading is already hard enough for most people.

通常最好每个线程使用一个上下文,无论是作为父/子上下文还是作为独立的上下文,但上述方法也可以。

It's generally better to use one context per thread, either as parent/child contexts or as independent contexts, but the approach above also works.

作为其结果,实际上设法保存假的对象,唯一真正的追索是获取这些对象,并修复或删除它们。如何识别这些对象取决于你的数据模型 - 没有通用的测试这个对象是什么?任何支票都取决于您的应用程式认为是正确的。

If you've actually managed to save bogus objects as a result of this, the only real recourse is to fetch those objects and either fix them up or delete them. How to identify these objects depends on your data model-- there's no universal test for "is this object crap?". Any checks depend on what your app considers to be correct.

这篇关于“核心数据不能实现故障”对于在主线程上的appDelegate managedObjectContext中创建的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆