Ios dispatch_get_current_queue()已弃用,是否有安全CoreData的替代方案?

Ios dispatch_get_current_queue()已弃用,是否有安全CoreData的替代方案?,ios,core-data,grand-central-dispatch,Ios,Core Data,Grand Central Dispatch,许多人问了一个标题相似但目的却截然不同的问题: CoreData要求您跟踪当前队列、当前线程和当前NSOperationQueue(如果您是一个NSOperation),如果您允许来自其他类的方法调用(默认情况下,每个类都允许)。关于这一点没有“可能”:这是一个严格的要求 这很好,通常很容易确保: NSAssert( [NSThread currentThread].isMainThread || myPrivateQueue == dispatch_get_current_queue(), @

许多人问了一个标题相似但目的却截然不同的问题:

CoreData要求您跟踪当前队列、当前线程和当前NSOperationQueue(如果您是一个NSOperation),如果您允许来自其他类的方法调用(默认情况下,每个类都允许)。关于这一点没有“可能”:这是一个严格的要求

这很好,通常很容易确保:

NSAssert( [NSThread currentThread].isMainThread || myPrivateQueue == dispatch_get_current_queue(), @"You tried to call this method from an external thread, or a queue other than my internal private queue. That's not legal, and will cause data corruption" );
…除了苹果已经不赞成dispatch_get_current_queue(),显然是“因为人们滥用它来绕过GCD中缺失的功能/他们不理解的GCD位”

注意:从苹果的标题评论来看,我上面对dispatch_get_current_queue()的使用似乎是正确的,没有滥用:关键是我正在检查队列是否是我创建的私有队列(苹果声称这是可以接受的用法)

撇开仅仅因为实现中的缺陷而否定某个东西的智慧不谈:(…有没有人找到了一个解决办法,让苹果删除这个问题。特别是:有了CoreData,你必须跟踪队列-还有其他方法吗


(这很重要,因为:对于CoreData,如果您允许某些东西意外调用这样的方法,您不会得到“崩溃”,您将得到“数据损坏,在将来的某个时候,当修复它为时已晚时会出现”)

performBlock
始终在正确的线程中运行它。只需使用:

[yourManagedObjectContext performBlock:^{
//do your stuff here
}];

您不再需要跟踪当前上下文,因为您的MOC知道哪个线程首先触发此MOC。当您使用
performBlock
performBlock和wait
时,您是安全的。

在我的特定情况下,我将所有performBlock调用替换为:

  • 将所有CoreData操作移动到单个类
  • 创建专用调度队列
  • 将所有内部呼叫合并为一个呼叫
  • 单个调用将自己包装在一个dispatch_async((专用内部队列))中
  • …它在调度中做的第一件事是“if(self.privateMOC==nil)”…并创建本地MOC,从而确保只有在一个队列上才能访问和创建MOC
  • 发生了两件事:

  • 互斥锁/锁挂起已全部消失(尽管这可能是巧合-如果锁仍然处于死锁状态,我将稍后报告)
  • 性能明显优于performBlock:在任何地方都可以使用
  • 注意:我们有很多performBlock调用,并且经常这样做(敏感数据需要以中等频率更改CoreData MOC内容)。我不知道这在普通应用程序中是否会有明显的区别

  • …因此,就目前而言,就我的目的而言:这已被证明是一个很好的解决方案。我不认为这是对这个问题的“正确”的一般性答案,但…我向任何发现“performBlock”并不像表面上那样是万灵药的人推荐它。

    好主意,但它似乎在复杂情况下的线程锁定和性能方面存在问题-通过“问题”我的意思是“可能是CoreData问题,也可能是我们的代码库中的bug,可能两者都有”。我的第一步是开始自由地断言,以找出为什么偶尔会出现“CoreData在一个互斥体上挂起数十秒,而互斥体似乎没有争议”…因此我试图消除我们对“所有事情都始终使用performBlock”的依赖并找出实际发生/未发生的事情“总是
    performBlock:
    for everything”几乎是一种推荐的快速处理方式。
    dispatch\u get\u current\u queue()
    基本上是无用的,因为libdispatch的工作方式——有少量的“全局”队列和其他队列最终以要在这些队列上执行的操作为目标。这会导致该调用无效,因为当前队列是哪个?它在哪个队列上排队?还是它在哪个全局队列上执行。排队器是您在哪个队列上的仲裁者。在这种情况下,
    performBlock:
    是排队器,并且是唯一的方法我知道你在那个队列中。对于我在这里询问的应用程序,我一直在使用
    dispatch\u queue\u set\u specific()
    dispatch\u get\u specific()
    ,它在识别特定队列方面工作得很好。Jody对答案的评论提到在核心数据中使用类似的东西。@BradLarson dispatch\u get\u specific()非常有趣,谢谢。我不确定当您不在块内时调用它会发生什么(在正确的执行中,您可能会这样做,但我想知道当它出错时会发生什么,因为这是我试图捕获/断言/记录的设置)我不知道是否在块中很重要。它所测试的只是分配给该代码运行的特定队列的一个键。正如我在这里所展示的,我将其用于一个函数,该函数通过同步地将块分配给队列或直接运行代码(如果已经在t上)来保证在特定队列上同步执行代码hat队列。
    dispatch\u get\u current\u queue()
    被弃用,因为API的设计有缺陷,而不是实现有缺陷。您使用的预期替换功能确实是
    dispatch\u get\u specific()
    @BradLarson如果你把它作为一个答案,我会把它标记为正确的。SimpleMan的答案很好,但我认为它更多的是一种变通方法,而不是直接的解决方案。