这行代码是在我的 awakeFromFetch
方法中调用的,该方法位于实现 NSManagedObject
的自定义托管对象中 . 这一行特别是调用我的名为 sharedManager
的单例网络管理器类 .
[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ];
dispatch_once块将被命中,如下所示 . 请注意,它以良好的方式实现,如here所示:
然后dispatch_once调用转到once.h并在此处在突出显示的行上冻结:
这是堆栈跟踪:
尝试加载以前保存的网络队列文件时,所有这些都会发生 . 应用程序完全关闭以保存,然后再次启动,然后发生冻结/锁定 .
我甚至尝试使用此代码来解决问题here,并且它不起作用 . 但是改变这个可能无关紧要,因为我原来的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];});
});
}
到目前为止,这些是我解决此类问题的来源:
-
Code execution stops on using thread safe Singleton initialization code
-
http://cocoasamurai.blogspot.jp/2011/04/singletons-your-doing-them-wrong.html
-
http://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
谢谢你的帮助!
2 回答
该死的儿子,这是一个很好的提问 .
这里的问题是对dispatch_once的递归调用将会死锁 . 如果您需要确切的详细信息,you can find them with the source here . 所以你需要重写以避免这种情况 .
我的观点是,有一个建筑失误,无论什么导致这个呼叫 . 你绝对不希望做任何在执行时间内可能无限制的事情,因为关闭并从
dispatch_once
中的磁盘加载东西 . 你想要做的是创建一个可寻址的单例并返回的绝对最小值 . 然后,给它一个"Initializing"的内部状态,并将磁盘加载的东西运送到某个地方的非阻塞队列 . 那样的所有东西都没有"Initialized"状态,或类似的东西 .感谢alexcurylo的帮助,排除loadFromDisk作业解决了这个问题 . 为了使人们不会感到困惑,只需要使用下面的代码,我就会从磁盘中排队一个加载数组(用作保存的用户请求队列)的作业 . 您可以对任何作业进行排队,例如加载图像等 . 我的sharedManager类中的以下代码(从磁盘加载的位置)起作用,如下所示: