更改属性后,核心数据复制托管对象

时间:2019-04-09 18:29:03

标签: ios core-data nsmanagedobject nsmanagedobjectcontext

考虑我在上下文中有一个任意对象。

我正在使用具有此对象的父上下文创建一个新上下文。

context2 = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
context2.parentContext = parentContext;

在这个新的上下文中,我要做这样的事情,以便在自己的上下文中更改对象:

NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *contextObj = [context2 objectWithID:objectID];

如果我现在在上下文中进行访存,它将仅显示1个对象,这是预期的。但是一旦我做 contextObj.name = @"blah"; 相同的提取操作不会返回2个对象

一个拥有原始名称,另一个拥有“ blah”;

原始名称的对象的objectID设置为isTemporary,而“ blah”的对象的ID设置为NO。

为什么上下文会使用旧值复制对象?

例如:

NSManagedObjectContext *context2 = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
context2.parentContext = parentContext;

NSManagedObject *contextObj = [context2 objectWithID: myObject.objectID];
//If I do a NSFetchRequest here on the context2, there's only 1 object

contextObj.name = @"test";
//Now, the fetch has 2 objects

编辑: 这是复制问题的代码:

#import "ViewController.h"
#import "CustomObject+CoreDataClass.h"
#import "SecondCustomObject+CoreDataClass.h"
#import "AppDelegate.h"

@interface ViewController ()

@property (nonatomic, strong) NSManagedObjectContext *secondContext;
@property (nonatomic, strong) SecondCustomObject *secondObject;
@property (nonatomic, strong) NSPersistentContainer *persistentContainer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 250, 100)];
    [button setTitle:@"Tap here multiple times" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button addTarget:self action:@selector(triggerIssue) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    self.persistentContainer = appDelegate.persistentContainer;

    [self setupConfig];
}

- (void)setupConfig {
    NSManagedObjectContext *firstContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    firstContext.parentContext = self.persistentContainer.viewContext;
    firstContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;

    self.secondContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    self.secondContext.parentContext = firstContext;
    self.secondContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;

    self.secondObject = [[SecondCustomObject alloc] initWithContext:self.secondContext];
    self.secondObject.name = @"Name1";
}

//Needs to be triggered 2-3 times for the issue to happen
- (void)triggerIssue {
    [self.secondContext performBlock:^{
        [self.secondContext save:NULL];
        [self.persistentContainer.viewContext performBlock:^{
            [self.persistentContainer.viewContext save:NULL];
            NSLog(@"SAVED");
        }];
    }];

    [self.secondContext.parentContext refreshAllObjects];
    [self.secondContext.parentContext save:NULL];
    self.secondObject.name = @"Name2";
    [self print];
}

- (void)print {
    NSArray *result = [self.secondContext executeFetchRequest:SecondCustomObject.fetchRequest error:NULL];
    NSLog(@"Result Count [%lu]", (unsigned long)result.count);
    for (SecondCustomObject *obj in result) {
        NSLog(@"Obj Name [%@]", obj.name);
    }
    NSLog(@"-----");
}

几次调用triggerIssue之后,您开始在相同的上下文中看到重复的对象,这是一个输出示例:

CDTest[15510:761956] Result Count [1]
CDTest[15510:761956] Obj Name [Name2]
CDTest[15510:761956] -----
CDTest[15510:761956] SAVED
CDTest[15510:761956] Result Count [1]
CDTest[15510:761956] Obj Name [Name2]
CDTest[15510:761956] -----
CDTest[15510:761956] SAVED
CDTest[15510:761956] Result Count [2]
CDTest[15510:761956] Obj Name [Name2]
CDTest[15510:761956] Obj Name [Name2]
CDTest[15510:761956] -----
CDTest[15510:761956] SAVED

1 个答案:

答案 0 :(得分:0)

您不应该在save的父上下文中调用performBlock。您第二个上下文中的save会将您的更改传播到父上下文。

执行完该块并传播更改后,您可以保存主上下文。

删除这些行

 [self.persistentContainer.viewContext performBlock:^{
        [self.persistentContainer.viewContext save:NULL];
        NSLog(@"SAVED");
    }];
块中的

解决了该问题。在save之外执行的performBlock保存视图上下文。