ios - CoreData 嵌套上下文 : what is the proper way to save context?

标签 ios objective-c multithreading networking core-data

我正在使用嵌套上下文模式来支持 CoreData 的多线程工作。 我有 CoredDataManager 单例类,上下文的初始化是:

self.masterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.masterContext.persistentStoreCoordinator = self.persistentStoreCoordinator;

self.mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.mainContext.parentContext = self.masterContext;

对于来自 Web 服务的响应的每个插入操作,我使用我的 CoreDataManager 的 API 来获取新的托管上下文:

- (NSManagedObjectContext *)newManagedObjectContext {
    NSManagedObjectContext *workerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    workerContext.parentContext = self.mainContext;

    return workerContext;
}

它看起来像(PlayerView 类是 NSManagedObject 类的子类):

[PlayerView insertIfNeededByUniqueKey:@"playerViewId" value:playerViewId inBackgroundWithCompletionBlock:^(NSManagedObjectContext *context, PlayerView *playerView) {
    playerView.playerViewId = playerViewId;
    playerView.username = playerViewDictionary[@"name"];

    [context saveContextWithCompletionBlock:^{
         //do something
    } onMainThread:NO];//block invocation on background thread
}];

saveContextWithCompletionBlock 方法在 NSManagedObjectContext 类别中实现:

- (void)saveContextWithCompletionBlock:(SaveContextBlock)completionBlock onMainThread:(BOOL)onMainThread {
    __block NSError *error = nil;

    if (self.hasChanges) {
        [self performBlock:^{
            [self save:&error];

            if (error) {
                @throw [NSException exceptionWithName:NSUndefinedKeyException
                                               reason:[NSString stringWithFormat:@"Context saving error: %@\n%@\n%@", error.domain, error.description, error.userInfo]
                                             userInfo:error.userInfo];
            }

            if (completionBlock) {
                if (onMainThread && [NSThread isMainThread]) {
                    completionBlock();
                } else if (onMainThread) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        completionBlock();
                    });
                } else if ([NSThread isMainThread]) {
                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^{
                        completionBlock();
                    });
                } else {
                    completionBlock();
                }
            }
        }];
    }
}

然后在某个阶段我调用 CoreDataManager 的方法来保存主上下文:

- (void)saveMasterContext; {
    __block NSError *error;

    [self.mainContext performBlock:^{
        [self.mainContext save:&error];
        [self treatError:error];

        [self.masterContext performBlock:^{
            [self.masterContext save:&error];
            [self treatError:error];
        }];
    }];
}

我有两个主要类,NSManagedObject 的子类 - PlayerView 和 Post。 PlayerView 与 Post 具有一对多的关系。 PlayerView 已经保存好了。帖子永远不会保存,我收到错误消息:

CoreData:错误:从上下文中删除托管对象 0x17dadd80 (0x17daf930) 后对其进行变异。

我认为,问题在于上下文保存逻辑。

最佳答案

首先,您遇到的错误通常发生在您创建新托管对象的上下文在您有机会保存它之前消失(释放)时。

其次,确保上下文保存在适当线程中的最佳方法是使用 performBlockperformBlockAndWait 而不是试图找出上下文属于哪个线程至。这是一个安全保存上下文的示例“保存”函数:

+ (BOOL)save:(NSManagedObjectContext *)context {
    __block BOOL saved = NO;
    [context performBlockAndWait: {
        NSError *error;
        saved = [context save:&error];
        if (!saved) {
            NSLog("failed to save: %@", error);
        }
    }]
    return saved;
}

至于使用嵌套私有(private)上下文(主线程上下文作为父上下文),我们的团队遇到了该模型的一些问题(不记得到底是什么),但我们决定监听 NSManagedObjectContextDidSaveNotification 并使用 mergeChangesFromContextDidSaveNotification 更新上下文。

希望对您有所帮助。

关于ios - CoreData 嵌套上下文 : what is the proper way to save context?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22064878/

相关文章:

c# - 从数据库生成 1,000,000 个文件的最佳代码

ios - UIDatePicker 背景颜色在第二个 viewDidLoad 上发生变化

ios - UITableView 中的数据源和委托(delegate)是如何工作的?

ios - tableViewHeader 的 subview 上的 setFrame 不起作用

iphone - 如何缩短 Cocos2D 粒子生命周期?

objective-c - XCode - UIScrollView 分页不显示 subview (自动布局?)

iphone - 在圆形叠加层中绘制文本

java - Redisson-netty 线程没有关闭

python - 多线程在同一程序中运行UDP客户端和UDP服务器

ios - 如何在 Swift 中从当年的每个月中获取一半