核心数据保存但不保存 - 专用队列跳转线程
Posted
技术标签:
【中文标题】核心数据保存但不保存 - 专用队列跳转线程【英文标题】:Core data saving but not saving - Dedicated queue jumping threads 【发布时间】:2015-10-07 22:42:34 【问题描述】:我正在尝试在后台运行同步引擎,并且正在使用 NSPrivateQueueConcurrencyType
,如下所示:
- (NSManagedObjectContext *)workerContext
NSManagedObjectContext* workerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
workerContext.parentContext = self.mainContext;
return workerContext;
我想我需要一个专用的后台队列,所以我也创建了这个:
- (dispatch_queue_t)syncQueue
if (!_syncQueue)
_syncQueue = dispatch_queue_create("com.me.syncEngineSyncQueue", 0);
return _syncQueue;
我遇到了一个 NSManagedObject 删除正在发生的问题,但是,它被逆转了。我目前的猜测是它与线程有关。
我在同步引擎中记录了断点,并注意到相同的syncQueue
在不同的时间在不同的线程上运行。这可能是我的问题吗?
如果是这样,我如何创建一个在一个线程上一致运行的 dispatch_queue?
【问题讨论】:
【参考方案1】:我想我需要一个专用的后台队列,所以我创建了这个 还有:
Bzzzzt。错误的。 Core Data 会为您解决这个问题。当您使用NSPrivateQueueConcurrencyType
初始化您的 MOC 时,它带有自己的内部管理的 GCD 队列。你根本不用管它。
但是,与该 MOC 相关的任何工作必须通过 performBlock
API for NSManagedObjectContext
完成。除其他外,该 API 基本上将您的块放在特殊的私有 GCD 队列中,并安排它执行。
如果是这样,我如何创建一个在一个上始终运行的 dispatch_queue 线程?
你没有。这就是 GCD 之美的一部分。您将代码块插入消息队列,“一些”线程将它们剥离并执行它们。你可能不太关心哪个线程正在这样做(除了主队列的东西)。
编辑
明白了。但是,我仍然需要保存 mainContext 这是 我的workerContext的父母,对吧?我需要在 主线程?现在我正在做 [self.mainContext save:&error];在 使用保存workerContext后的主线程 performBlockAndWait – Ramsel 5 小时前
您最好将每个上下文视为自己的实体,并且仅“利用”在与 UI 元素交互时知道主上下文在主线程上运行,这需要在主线程上进行交互。
如果你想在保存子后保存父上下文,请执行以下操作,这是NSManagedObjectContext
上的一个可能的类别方法。
- (void)_saveRecursively:(BOOL)recursiveSave
withCompletion:(void(^)(NSError *error))completion
NSError *error;
if ([self save:&error])
error = nil;
NSManagedObjectContext *parent = self.parentContext;
if (parent != nil && recursiveSave)
return [parent performBlock:^
[parent _saveRecursively:recursiveSave withCompletion:completion];
];
completion(error);
上述方法是“私有的”,不应暴露。它保存当前上下文。如果要求进行递归保存,它将继续保存层次结构,直到它到达末尾,或者直到其中一个保存操作失败。
然后它将调用完成处理程序,如果失败则传递 NSError
的实例,如果成功则传递 nil
。
- (void)saveRecursively:(BOOL)recursiveSave
withCompletion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion
[self _saveRecursively:recursiveSave withCompletion:^(NSError *error)
if (completion)
[self performBlock:^
completion(self, error);
];
];
此方法为用户提供类别 API。它确保从原始保存上下文的受保护范围内异步调用完成块。这样,您可以保证完成块可以安全使用,而无需调用另一个performBlock
。
- (void)saveWithCompletion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion
[self saveRecursively:YES withCompletion:completion];
这为异步保存整个层次结构提供了一种方便的方法。
这意味着你可以像这样调用save方法...
[childContext saveWithCompletion:^(NSManagedObjectContext *moc, NSError *error)
// moc will be the same as childContext, and you can use the variable moc
// safely, knowing this block is running in its own performBlock
if (error)
// Handle the save error
else
// Handle the successful save
];
【讨论】:
明白了。但是,我仍然需要保存mainContext
,它是我的workerContext
的父级,对吧?我需要在主线程中调用该保存吗?现在我在使用performBlockAndWait
保存workerContext
后在主线程中做[self.mainContext save:&error];
以上是关于核心数据保存但不保存 - 专用队列跳转线程的主要内容,如果未能解决你的问题,请参考以下文章