Основные данные, дублирующие управляемый объект после изменения свойств - PullRequest
1 голос
/ 09 апреля 2019

Учтите, что у меня есть произвольный объект в контексте.

Я создаю новый контекст с родительским контекстом, который имеет этот объект.

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

В этом новом контексте я делаю что-то подобное, чтобы изменить объект в своем собственном контексте:

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

если я сейчас извлекаю контекст, он отображает только 1 объект, что ожидается. Но однажды я contextObj.name = @"blah"; та же самая выборка не возвращает 2 объекта

У одного есть оригинальное имя, у другого "бла";

И тот, у кого с оригинальным именем есть isTemporary, для его objectID установлено значение YES, а для того, у кого "blah", установлено значение NO.

есть идеи, почему контекст создает копию объекта со старым значением?

Ex:

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

Edit: Вот код, который повторяет проблему:

#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 голосов
/ 14 апреля 2019

Вы не должны вызывать save в родительском контексте в вашем performBlock. save в вашем втором контексте распространяет ваши изменения в родительский контекст.

Как только блок выполнен и изменения распространены, вы можете сохранить свой основной контекст.

Удаление этих строк

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

из блока решает проблему. save, выполненный вне performBlock, сохраняет контекст представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...