dealloc вызвал аварийное приложение фоновой очереди GCD, созданное с помощью ARC

У меня есть контроллер представления, который загружает ресурс в фоновой очереди GCD. Я передаю своей функции загрузки блок обратного вызова для выполнения после завершения загрузки, и он всегда выполняет этот блок в основном потоке.

Проблема возникает, если мой контроллер представления отклоняется пользователем до завершения загрузки. Я подозреваю, что происходит следующее: как только мой контроллер представления отклоняется, блок обратного вызова - единственное, что сохраняет сильную ссылку на контроллер. Блок обратного вызова сохраняется только в фоновом потоке, поэтому после его освобождения все объекты, захваченные в области блока обратного вызова, также освобождаются, хотя и в фоновой очереди.

Это проблема: освобождение в фоновой очереди вызывает выполнение функции dealloc в той же очереди, а не в основной очереди. Это, в свою очередь, вызывает dealloc в фоновом режиме, и приложение вылетает:

2012-01-19 12:47:36.349 500px iOS[4892:12107] bool _WebTryThreadLock(bool), 0x306c10: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
[Switching to process 16643 thread 0x4103]
[Switching to process 16643 thread 0x4103]
(gdb) where
#0  0x307fd3c8 in _WebTryThreadLock ()
#1  0x307ff1b0 in WebThreadLock ()
#2  0x33f7865e in -[UITextView dealloc] ()
#3  0x0005d2ce in -[GCPlaceholderTextView dealloc] (self=0x309010, _cmd=0x340ce6b8) at /Users/ash/Dropbox/500px/500px-ios/500px iOS/500px iOS/GCPlaceholderTextView.m:113
#4  0x337cac42 in -[NSObject(NSObject) release] ()
#5  0x33dee5f4 in -[UIView(Hierarchy) removeFromSuperview] ()
#6  0x33e836cc in -[UIScrollView removeFromSuperview] ()
#7  0x33f762f0 in -[UITextView removeFromSuperview] ()
#8  0x33e01de2 in -[UIView dealloc] ()
#9  0x337cac42 in -[NSObject(NSObject) release] ()
#10 0x33dee5f4 in -[UIView(Hierarchy) removeFromSuperview] ()
#11 0x33e01de2 in -[UIView dealloc] ()
#12 0x33f437e4 in -[UIScrollView dealloc] ()
#13 0x337cac42 in -[NSObject(NSObject) release] ()
#14 0x33dee5f4 in -[UIView(Hierarchy) removeFromSuperview] ()
#15 0x33e836cc in -[UIScrollView removeFromSuperview] ()
#16 0x33e01de2 in -[UIView dealloc] ()
#17 0x337cac42 in -[NSObject(NSObject) release] ()
#18 0x33dee5f4 in -[UIView(Hierarchy) removeFromSuperview] ()
#19 0x33e01de2 in -[UIView dealloc] ()
#20 0x337cac42 in -[NSObject(NSObject) release] ()
#21 0x33e5a00e in -[UIViewController dealloc] ()
#22 0x00035f16 in -[PXPhotoViewController dealloc] (self=0x5158d0, _cmd=0x340ce6b8) at /Users/ash/Dropbox/500px/500px-ios/500px iOS/500px iOS/PXPhotoViewController.m:118
#23 0x337cac42 in -[NSObject(NSObject) release] ()
#24 0x337e5046 in sendRelease ()
#25 0x331fc92e in _Block_object_dispose ()
#26 0x0003c33a in __destroy_helper_block_ () at /Users/ash/Dropbox/500px/500px-ios/500px iOS/500px iOS/PXPhotoViewController.m:878
#27 0x331fc88e in _Block_release ()
#28 0x331fc91c in _Block_object_dispose ()
#29 0x000c8d32 in __destroy_helper_block_ () at /Users/ash/Dropbox/500px/500px-ios/500px iOS/500px iOS/PXPhotoFetcher.m:557
#30 0x331fc88e in _Block_release ()
#31 0x35eec8ec in _dispatch_call_block_and_release ()
#32 0x35ee2de2 in _dispatch_queue_drain ()
#33 0x35ee2f32 in _dispatch_queue_invoke ()
#34 0x35ee24f2 in _dispatch_worker_thread2 ()
#35 0x34ecb590 in _pthread_wqthread ()
#36 0x34ecbbc4 in start_wqthread ()

Код, который я выполняю в основном потоке, выглядит следующим образом:

[[PXPhotoFetcher sharedPXPhotoFetcher] fetchPhotoDetailsWithPriority:PhotoRequestLowPriority 
    withCallback:^(PXPhotoModel *thePhotoModel) {
        // a callback function which captures self in its scope
    } forModel:model];

Я создаю для 4.3, поэтому, если я использую ссылка __unsafe_unrehibited на себя в блоке обратного вызова, это решит мою текущую проблему, но представит новую проблему наличия висячего указателя.

Что вы порекомендуете для разработки решения для этого? Другие обходные пути включали переопределение выпуска , так что он всегда вызывался в основном потоке, но это, очевидно, не будет работать в среде ARC.

Похоже, это должна быть гораздо более распространенная проблема с ARC и GCD, но я не могу найти ничего в Интернете. Это просто потому, что я нацелен на

10
задан Community 23 May 2017 в 11:58
поделиться