这行代码在我的 awakeFromFetch
方法中调用,该方法位于实现 NSManagedObject
的自定义托管对象内。这一行特别调用了我的名为 sharedManager
的单例网络管理器类。
[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ];
dispatch_once block 将被命中,如下所示。请注意,它以一种很好的方式实现,如图所示 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://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
- ios singleton class crashes my app
- http://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
- http://www.bignerdranch.com/blog/dispatch_once-upon-a-time/
感谢您的帮助!
最佳答案
该死的 child ,这是一个很好的提问工作。
这里的问题是对 dispatch_once 的递归调用会死锁。如果您需要确切的详细信息,you can find them with the source here .所以你需要重写以避免这种情况。
我的观点是,导致此 -loadQueueFromDisk
调用的任何因素都存在架构失误。您绝对不想做任何在执行时间上可能不受限制的事情,就像在 dispatch_once
中关闭并从磁盘加载某些东西一样。你想要做的是创建一个可寻址的单例并退出的绝对最低限度。然后,给它一个“初始化”的内部状态,并将磁盘加载的东西传送到某个地方的非阻塞队列中。这样,所有不依赖于从磁盘加载的东西的东西都可以继续,而所有依赖于从磁盘加载的东西的东西都可以将自己添加到磁盘加载所在的队列中,或者每隔几百毫秒检查一次以查看如果它处于“已初始化”状态,或者类似的状态。
关于ios - 分派(dispatch)一次 (dispatch_once) 单例在 objective-c 中卡住/锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28596305/