CoreData - 如何使对象在不同的​​线程/上下文中保持最新?

Posted

技术标签:

【中文标题】CoreData - 如何使对象在不同的​​线程/上下文中保持最新?【英文标题】:CoreData - how to keep the object up-to-date in a different thread/context? 【发布时间】:2014-08-30 06:47:55 【问题描述】:

我的应用程序有 2 个ManagedObjects:ArticleList。它们之间存在多对多关系(一篇文章可以在多个列表中;该列表可以包含多篇文章)。

在文章的 UI 中,我有一个 + 按钮,它显示(在弹出框控制器中)Lists 的列表,并允许从其中添加或删除文章。

所以在ArticleViewController 中,我将Article 对象的一个​​实例作为属性:self.article

ListsTableViewController *contentViewController = [[ListsTableViewController alloc] initWithStyle:UITableViewStylePlain];
contentViewController.selectionBlock = ^(BOOL wasSelected, List *list) 
    NSLog(@"%@ was%@ selected?", list, wasSelected ? @"" : @" not");
    if (wasSelected) 
        [self.article addToList:list];
     else 
        [self.article removeFromList:list];
    
;

self.myPopoverController = [[WEPopoverController alloc] initWithContentViewController:contentViewController];
contentViewController.selectedLists = [NSMutableArray arrayWithArray:[[self.article.lists allObjects] valueForKeyPath:@"objectID.URIRepresentation"]];
[contentViewController viewDidAppear:YES];
[self.myPopoverController presentPopoverFromBarButtonItem:sender
                                 permittedArrowDirections:UIPopoverArrowDirectionAny
                                                 animated:YES];

我将列表中的objectID.URIRepresentations 的列表传递给contentViewController,它允许我最初在最初选择的列表上显示复选标记。

Article 对象的addToList:removeFromList: 方法如下所示(我在我的项目中使用MagicalRecord):

- (void) addToList:(List *)list

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) 
        List *l = [list MR_inContext:localContext];
        Article *n = [self MR_inContext:localContext];

        NSMutableSet *s = [NSMutableSet setWithSet:n.lists];
        [s addObject:l];
        n.lists = s;
        s = [NSMutableSet setWithSet:l.articles];
        [s addObject:n];
        l.articles = s;
     completion:nil
  ];

当我第一次输入ArticleViewController 并点击+ 按钮时,它会正确显示文章所在的列表。但是,当我从那里的列表中添加/删除时,请关闭弹出视图控制器并打开再说一遍,self.article 似乎没有设置更新的列表(它们似乎被添加到不同的线程/上下文中并且没有传播到这个?)。我第一次看到那里的清单。

退出ArticleViewController 并返回解决了问题(强制重新读取),但在第一次添加后问题仍然存在。

如何使Article中设置的Lists在被访问时强制重新获取关系?

【问题讨论】:

你为什么要NSMutableSet *s = [NSMutableSet setWithSet:n.lists];?你为什么不使用 KVC 访问器来处理关系? 【参考方案1】:

经过几个小时的反复试验,我找到了一个可行的解决方案(至少目前可行)。我不确定它有多智能

- (void) addToList:(List *)list

    __block NSSet *set;
    NSManagedObjectContext *c = self.managedObjectContext;
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) 
        List *l = [list MR_inContext:localContext];
        Article *n = [self MR_inContext:localContext];

        NSMutableSet *s = [NSMutableSet setWithSet:n.lists];
        [s addObject:l];
        n.lists = s;
        set = n.lists;
     completion:^(BOOL success, NSError *error) 
        NSMutableSet *set2 = [NSMutableSet set];
        for (List *l in [set allObjects]) 
            [set2 addObject:[l MR_inContext:c]];
        
        self.lists = set2;
    ];

- (void) removeFromList:(List *)list

    __block NSSet *set;
    NSManagedObjectContext *c = self.managedObjectContext;
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) 
        List *l = [list MR_inContext:localContext];
        Article *n = [self MR_inContext:localContext];

        NSMutableSet *s = [NSMutableSet setWithSet:n.lists];
        [s removeObject:l];
        n.lists = s;
        set = n.lists;
     completion:^(BOOL success, NSError *error) 
        NSMutableSet *set2 = [NSMutableSet set];
        for (List *l in [set allObjects]) 
            [set2 addObject:[l MR_inContext:c]];
        
        self.lists = set2;
    ];

【讨论】:

以上是关于CoreData - 如何使对象在不同的​​线程/上下文中保持最新?的主要内容,如果未能解决你的问题,请参考以下文章

CoreData 多线程删除

CoreData Context合并后如何获取对象

如何从 CoreData 获取完整的对象(不是故障)?

CoreData 和一对多关系的并发错误

CoreData 和并发:无法解释的行为

如何使事件回调进入我的 win 表单线程安全?