Dispatch once(dispatch_once)singleton冻结/锁定目标c

Mar*_*cel 9 xcode singleton objective-c grand-central-dispatch ios

这行代码是在我的awakeFromFetch方法中调用的,该方法位于实现的自定义托管对象中NSManagedObject.这一行特别是调用我的单件网络管理器类调用sharedManager.

[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ];
Run Code Online (Sandbox Code Playgroud)

dispatch_once块将被命中,如下所示.请注意,这是一个很好的方式来实现如图所示在这里:

在此输入图像描述

然后dispatch_once调用转到once.h并在此处在突出显示的行上冻结:

dipatch_once更深

这是堆栈跟踪:

堆栈跟踪

尝试加载以前保存的网络队列文件时,所有这些都会发生.应用程序完全关闭以保存,然后再次启动,然后发生冻结/锁定.

我甚至尝试使用此代码来解决此处建议的问题,但它不起作用.但是改变这个可能无关紧要,因为我原来的dispatch_once代码已经很好地工作了很长时间.只是在这种特殊情况下.

if ([NSThread isMainThread]) 
{
    dispatch_once(&onceToken, ^{
    stack = [[KACoreDataStack alloc] init];});
} 
else 
{
    dispatch_sync(dispatch_get_main_queue(), ^{
    dispatch_once(&onceToken, ^{
    stack = [[KACoreDataStack alloc] init];});
});
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,这些是我解决此类问题的来源:

谢谢你的帮助!

Ale*_*ylo 6

该死的儿子,这是一个很好的提问.

这里的问题是对dispatch_once的递归调用将会死锁.如果您需要确切的详细信息,可以在此处找到源代码.所以你需要重写以避免这种情况.

我的观点是,有一个建筑失误,无论什么导致这个-loadQueueFromDisk电话.你绝对希望做任何在执行时间可能无限制的事情,因为关闭并从磁盘内部加载一些东西dispatch_once.你想要做的是创建一个可寻址的单例并返回的绝对最小值.然后,给它一个内部状态"正在初始化",并将磁盘加载的东西运送到某个地方的非阻塞队列.这样,所有不依赖于从磁盘加载的东西的东西都可以继续,并且所有依赖于从磁盘加载的东西的东西都可以将自己添加到磁盘加载所在的队列中,或者每隔几百毫秒检查一下如果它还处于"已初始化"状态,或者沿着那些方向.


Mar*_*cel 0

感谢 alexcurylo 的帮助,排队 loadFromDisk 作业解决了这个问题。为了不让人们感到困惑,碰巧的是,通过下面的代码,我正在排队一个从磁盘加载数组(充当保存的用户请求队列)的作业。您可以对任何作业进行排队,例如加载图像等。我的sharedManager类中的以下代码(正在调用从磁盘加载)起作用,如下所示:

-(void) loadQueueFromFileByQueueing
{
  //Create a Queue
  /* Note that fileStrQueue should be added to the .h file as NSOperationQueue *fileStrQueue;*/
  fileStrQueue = [[NSOperationQueue alloc] init];

  //Create an  operation which will invoke method loadQueueFromDisk
  NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadQueueFromDisk) object:nil];

  //Add this operation to the queue
  [fileStrQueue addOperation:operation];

  //Releasing the above operation as it is already retained by the queue.
  // [operation release]; // If you are using ARC, this won't be necessary
}
Run Code Online (Sandbox Code Playgroud)