Magical Record检测到默认上下文中没有变化

时间:2015-03-03 01:09:00

标签: ios objective-c multithreading core-data magicalrecord

我正在为我的应用程序使用魔法记录,所以我可以利用他们的核心数据堆栈,它应该自动将我在工作者上下文(核心数据线程)中的更改传播到(主线程的)默认上下文。我一直在核心数据写入队列中创建和更新我的对象,一切正常。

然后我遇到了这个问题,Magical Record能够在我的工作环境中保存我的更改,但是当它尝试保存到默认上下文时,它检测不到任何更改,因此无法保存。

我哪里做错了?在我的应用程序的其余部分,我正在以相同的方式创建和更新它的工作原理。请帮忙。谢谢!

以下是相关代码:

在所有这些变化之后未检测到任何变化:

dispatch_async(CoreDataWriteQueue(), ^{
    if (self.person) {
        FTPerson *localPerson = [FTPerson fetchWithID:self.person.id];
        [localPerson setName:self.nameField.text];
        [localPerson trainWithImages:self.addedImages];
    } else {
        FTPerson *newPerson = [[FTPerson alloc] initWithName:self.nameField.text andInitialTrainingImages:self.addedImages];
        FTGroup *localGroup = [FTGroup fetchWithID:self.group.id];
        [newPerson addGroup:localGroup];
    }
    [[NSManagedObjectContext MR_contextForCurrentThread] MR_saveToPersistentStoreAndWait];
});

我也尝试过saveWithBlock方法,但没有运气:

dispatch_async(CoreDataWriteQueue(), ^{
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext){
        if (self.person) {
            FTPerson *localPerson = [FTPerson fetchWithID:self.person.id];
            [localPerson setName:self.nameField.text];
            [localPerson trainWithImages:self.addedImages];
        } else {
            FTPerson *newPerson = [[FTPerson alloc] initWithName:self.nameField.text andInitialTrainingImages:self.addedImages];
            FTGroup *localGroup = [FTGroup fetchWithID:self.group.id];
            [newPerson addGroup:localGroup];
        }
    }];
});

这是我创建人物和组对象的地方:

dispatch_async(CoreDataWriteQueue(), ^{
        FTPerson *newPerson = [[FTPerson alloc] initWithName:@"test" andInitialTrainingImages:@[[UIImage imageNamed:@"test.jpg"]]];
    });

dispatch_async(CoreDataWriteQueue(), ^{
        FTGroup *newGroup = [[FTGroup alloc] init];
        [self setGroup:newGroup];
    });

也是init方法:

- (id)initWithName:(NSString *)name andInitialTrainingImages:(NSArray *)images {
    NSManagedObjectContext *context = [NSManagedObjectContext     MR_contextForCurrentThread];
    self = [FTPerson MR_createInContext:context];
    self.name = name;
    self.id = [[NSUUID UUID] UUIDString];
    self.objectIDString = [[self.objectID URIRepresentation] absoluteString];
    self.trainingImages = [[NSMutableArray alloc] init];
    [context MR_saveToPersistentStoreAndWait];
    return self; 
}

- (id)init {
    NSManagedObjectContext *context = [NSManagedObjectContext MR_contextForCurrentThread];
    self = [FTGroup MR_createInContext:context];

    self.id = [[NSUUID UUID] UUIDString];

    self.didFinishTraining = NO;
    self.didFinishProcessing = NO;
    self.photosTrained = @(0);
    self.lastProcessedDate = [NSDate date];

    [context MR_saveToPersistentStoreAndWait];
    return self;
}

固定

所以问题最终与魔法记录无关。 我错误地将对象添加到我的核心数据NSSet。而不是使它成为NSMutableSet并执行addObject:,我应该:

NSMutableSet *mutablePhotos = [self mutableSetValueForKey:@"photos"];
[mutablePhotos addObject:photo];

2 个答案:

答案 0 :(得分:1)

所以问题最终与魔法记录无关。我错误地将对象添加到我的核心数据NSSet。而不是使它成为NSMutableSet并执行addObject:,我应该:

NSMutableSet * mutablePhotos = [self mutableSetValueForKey:@“photos”]; [mutablePhotos addObject:photo];

答案 1 :(得分:0)

在处理Core Data时,我认为您不应该使用自己的调度队列。 -performBlock:上的NSManagedObjectContext方法的重点是核心数据负责在正确的队列上执行提供的块。

现在回答你的问题。首先,您使用的是MagicalRecord 2.x还是3.0?如果是2.x,请确保使用develop分支,或者获取最新版本(此时为v2.3beta5)。最新的开发和发布分支有很多改进。

其次,我认为使用Core Data进行多线程处理时需要做两件事:

  1. 始终通过编辑方案并设置-com.apple.CoreData.ConcurrencyDebug 1
  2. 来启用并发调试
  3. 始终非常清楚您要使用的上下文。有一个原因是MagicalRecord团队不再推荐使用方法-MR_contextForCurrentThread。修改您的创建方法以将NSManagedObjectContext作为参数,以便对创建它的上下文毫无疑问。
  4. 尝试进行以下更改:

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext){
        if (self.person) {
            FTPerson *localPerson = [self.person MR_inContext:localContext];
            [localPerson setName:self.nameField.text];
            [localPerson trainWithImages:self.addedImages];
        } else {
            FTPerson *newPerson = [[FTPerson alloc] initWithName:self.nameField.text andInitialTrainingImages:self.addedImages inContext:localContext]; 
            FTGroup *localGroup = [self.group MR_inContext:localContext];
            [newPerson addGroup:localGroup];
        }
    }];
    

    人:

    - (id)initWithName:(NSString *)name andInitialTrainingImages:(NSArray *)images inContext:(NSManagedObjectContext*)context {
        self = [FTPerson MR_createInContext:context];
        self.name = name;
        self.id = [[NSUUID UUID] UUIDString];
        self.objectIDString = [[self.objectID URIRepresentation] absoluteString];
        self.trainingImages = [[NSMutableArray alloc] init];
        [context MR_saveToPersistentStoreAndWait];
        return self; 
    }
    

    对于Person,我注意到你传入了一个图像数组,但是你为一个新的实体分配了一个空数组。你的意思是这样做吗?

    组:

    -(id)initWithContext:(NSManagedObjectContext*)context {
        self = [FTGroup MR_createInContext:context];
    
        self.id = [[NSUUID UUID] UUIDString];
    
        self.didFinishTraining = NO;
        self.didFinishProcessing = NO;
        self.photosTrained = @(0);
        self.lastProcessedDate = [NSDate date];
    
        [context MR_saveToPersistentStoreAndWait];
        return self;
    }