【问题标题】:"performBlockAndWait:" block is not executed"performBlockAndWait:" 块未执行
【发布时间】:2015-10-05 13:13:35
【问题描述】:

我有一个类似的方法:

- (void)handleUpdate
{
   dispatch_sync(dispatch_get_main_queue(), ^{
      NSArray *objectIDs = [self.objectsInMainContext valueForKeyPath:@"objectID"];

      [self.privateContext performBlockAndWait: ^{
         // Some processing
      }];
   });
}

我所说的mainContext 关联到主队列,privateContext 关联到私有队列并且是mainContext 的子级。这个方法是从privateContext的私有队列中调用的,到达performBlockAndWait:调用的时候不是nil,但是执行没有进入block,也没有到达这个方法之后的任何代码...

我会在这里遗漏什么?

提前致谢

编辑:我在 Xcode 中没有出错,我在 performBlockAndWait: 块内的代码中设置的断点以及在此方法调用之后根本没有到达。

编辑 2:我更正了代码 sn-p,我访问的不是mainContext,而是与mainContext 关联的对象数组。

【问题讨论】:

  • 当您已经在私有上下文中时,为什么要进入主上下文以获取对象 ID 的任何具体原因?
  • @Mundi 抱歉,那行是错误的...我编辑问题
  • @Mundi 我需要将我在mainContext 中获得的对象传递给这个子上下文来执行我的更新。

标签: ios core-data concurrency nsmanagedobjectcontext


【解决方案1】:

如果handleUpdate如你所说从私有队列中被调用,那么这是一个典型的死锁。

您在私人队列中致电dispatch_sync。这意味着“等到它返回,然后再继续这个队列。”然后,在该块内,您将另一个块排入队列,该块必须等待在私有队列上运行并且在它运行之前不会返回。队列现在正在等待自己并且永远不会前进。

我怀疑你希望 dispatch_sync 在这里成为 dispatch_async

【讨论】:

  • 但是我需要访问块内的objectIDs数组,那么使用dispatch_async会不会出问题?
  • 从不同于privateContext的私有队列的异步线程调用handleUpdate,而不是在那里使用dispatch_async来获取主队列会更好吗?
  • 我认为这里没有一个单一的答案。您需要管理整个应用程序的并发性。不过,请确保您已经从核心数据并发部分开始:developer.apple.com/library/prerelease/ios/documentation/Cocoa/…。通常,您希望 Core Data 通过 NSPrivateQueueConcurrencyType 处理并发,而不是尝试在其上强制使用特定队列。
  • 我用NSPrivateQueueConcurrencyType初始化privateContext,但是我的mainContext与主线程相关联,我需要从privateContext获取它的对象...这就是为什么我首先访问main来自主队列的上下文对象,然后我尝试在其私有队列中执行私有上下文的块...
  • 似乎将dispatch_sync 更改为dispatch_async 并不能解决我的情况...
【解决方案2】:

好吧,你的情况至少有 1 件事是错误的:

在主线程上调用performBlockAndWait:(通过将其传递给主队列)。文档说performBlockAndWait:

在接收者的队列上同步执行给定的块。

由于该调用,您将在主线程上获得死锁(因为您在外部使用 dispatch_sync

dispatch_async 方式的更新: 问题不会消失。那是因为您仍将使用主队列(这意味着最后的主线程)和主 CD 上下文(这也意味着主线程)。问题是你让主线程等待,直到在同一个(主)线程上完成工作 - 只是一个开箱即用的死锁。

【讨论】:

  • 因为我需要访问块内的objectIDs,这应该是最好的方法:从不同于privateContext的私有队列的异步线程调用handleUpdate,或者使用@987654328 @获取主线程?
  • 我怀疑是否需要使用同步方法。但如果是,只需删除封闭的 dispatch_sync - 而是使用 NSPrivateQueueConcurrencyType 初始化您的上下文(使用 - (instancetype)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)type)。
  • 我使用dispatch_async获取主队列,因为我需要访问主上下文的对象,而mai上下文与主线程相关联...
  • 我刚刚尝试将dispatch_sync 更改为dispatch_async,但问题似乎仍然存在
【解决方案3】:

你有几个问题。

首先,您直接使用 GCD 序列化对 NSMainQueueConcurrency MOC 的访问。您应该永远不要使用除 CoreData 同步机制之外的任何东西来访问 CoreData。是的,从主线程访问NSMainQueueConcurrencyType MOC 是安全的。但是,你永远不应该直接使用 GCD……尤其是dispatch_sync

其次,您使用的是不可重入的dispatch_sync。它可以而且将会导致死锁。你几乎不应该使用这个功能。认为它是一种非常锋利的工具,用于解决非常具体的问题的唯一方法。

第三,您在子上下文中调用performBlockAndWait,这永远不应该这样做,因为它会导致死锁。一般来说,除非您真的知道自己在做什么,否则您应该避免使用非异步线程模型。

您的代码应该更像这样。每个performBlock 调用都会将一个块发布到消息队列中,该消息队列将独立于任何等待线程进行处理。

- (void)handleUpdate
{
    [self.mainContext performBlock:^{
        NSArray *objectIDs = [self.objectsInMainContext valueForKeyPath:@"objectID"];
        [self.privateContext performBlock: ^{
            // Some processing with objectIDs
        }];
    });
}

【讨论】:

    猜你喜欢
    • 2014-03-29
    • 2012-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 2021-03-19
    相关资源
    最近更新 更多