核心数据保存但不保存 - 专用队列跳转线程

时间:2015-10-07 22:42:35

标签: objective-c multithreading core-data grand-central-dispatch

我正在尝试在后台运行同步引擎,我正在使用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;
}

我遇到了一个N​​SManagedObject删除正在发生的问题,然而,它被颠倒了。我目前的猜测是它与线程有关。

我在同步引擎中记录了断点,发现同一个syncQueue在不同的时间运行在不同的线程上。这可能是我的问题吗?

如果是这样,我如何创建一个在一个线程上一致运行的dispatch_queue?

1 个答案:

答案 0 :(得分:0)

  

我认为我需要一个专用的后台队列,所以我已经创建了这个   以及:

Bzzzzt。错误。 Core Data会为您解决此问题。当您使用NSPrivateQueueConcurrencyType初始化MOC时,它带有自己的内部管理的GCD队列。你根本不用担心它。

但是,任何与该MOC 相关的工作必须通过performBlock NSManagedObjectContext API完成。除其他外,该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
    }
}];