ios - ASIHTTPRequest block释放问题
PHP中文网
PHP中文网 2017-04-17 11:30:01
0
1
765

最近在iOS4.3.3的机器上发现用asi的block会有很大概率产生crash.
用了ARC
crash表现情况为:bool _WebTryThreadLock(bool), 0x20a0fb20: 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...

2   libsystem_c.dylib                   0x3388b727 _sigtramp + 34;
3   WebCore                             0x31d363bf _ZL17_WebTryThreadLockb + 102;
4   WebCore                             0x31d381b1 WebThreadLock + 52;
5   UIKit                               0x3317265f -[UITextView dealloc] + 30;
6   CoreFoundation                      0x334afc43 -[NSObject(NSObject) release] + 30;
7   snstaoban                           0x00190ffb __arclite_objc_storeStrong + 54;
8   snstaoban                           0x0001e5ab -[ShareInputView .cxx_destruct] + 106;
9   libobjc.A.dylib                     0x3398d961 object_cxxDestructFromClass + 52;
10  libobjc.A.dylib                     0x3398fb15 object_cxxDestruct + 12;
11  libobjc.A.dylib                     0x3398fb25 objc_destructInstance + 12;
12  libobjc.A.dylib                     0x3398d917 object_dispose + 26;
13  CoreFoundation                      0x334afee5 -[NSObject(NSObject) dealloc] + 24;
14  UIKit                               0x32ffbec7 -[UIView dealloc] + 382;
15  UIKit                               0x33058739 -[UIImageView dealloc] + 64;
16  snstaoban                           0x0001d485 -[ShareInputView dealloc] + 120;
17  CoreFoundation                      0x334afc43 -[NSObject(NSObject) release] + 30;
18  UIKit                               0x32fe85f5 -[UIView(Hierarchy) removeFromSuperview] + 364;
19  UIKit                               0x32ffbde3 -[UIView dealloc] + 154;
20  CoreFoundation                      0x334afc43 -[NSObject(NSObject) release] + 30;
21  UIKit                               0x3305400f -[UIViewController dealloc] + 174;
22  snstaoban                           0x00070467 -[RootViewController dealloc] + 238;
23  snstaoban                           0x00015f21 -[ShareSetViewController dealloc] + 120;
24  CoreFoundation                      0x334afc43 -[NSObject(NSObject) release] + 30;
25  snstaoban                           0x00190f29 __arclite_objc_release + 20;
26  snstaoban                           0x00178723 __destroy_helper_block_160 + 10;
27  libsystem_blocks.dylib              0x365a688f _Block_release + 58;
28  CoreFoundation                      0x334e4285 -[__NSMallocBlock release] + 8;
29  snstaoban                           0x00190f29 __arclite_objc_release + 20;
30  snstaoban                           0x000733a9 __destroy_helper_block_64 + 12;
31  libsystem_blocks.dylib              0x365a688f _Block_release + 58;
32  CoreFoundation                      0x334e4285 -[__NSMallocBlock release] + 8;
33  CoreFoundation                      0x334b01a1 CFRelease + 68;
34  CoreFoundation                      0x334b5ba9 -[__NSArrayM dealloc] + 92;
35  CoreFoundation                      0x334afc43 -[NSObject(NSObject) release] + 30;
36  CoreFoundation                      0x334b01a1 CFRelease + 68;
37  CoreFoundation                      0x334b2ebb _CFAutoreleasePoolPop + 146;
38  libdispatch.dylib                   0x30df06a5 _dispatch_worker_thread2 + 372;
39  libsystem_c.dylib                   0x33881591 _pthread_wqthread + 264;
40  libsystem_c.dylib                   0x33881bc4 _init_cpu_capabilities + 4294967295||dep=58,idx=57

原因是asi的completionBlock和failureBlock在非主线程(Thread 1 name: Dispatch queue: com.apple.root.low-priority)被释放,然后controller, view接着在这个线程被释放导致crash.
测试了5.0一上也是在非主线程被释放, 但是不会导致crash.
但是4.3.3的模拟器block是在主线程被释放.
于是查看asi的代码发现一个trick.
在dealloc里有

	#if NS_BLOCKS_AVAILABLE
	[self releaseBlocksOnMainThread];
	#endif
#if NS_BLOCKS_AVAILABLE
- (void)releaseBlocksOnMainThread
{
	NSMutableArray *blocks = [NSMutableArray array];
	if (completionBlock) {
		[blocks addObject:completionBlock];
		[completionBlock release];
		completionBlock = nil;
	}
	if (failureBlock) {
		[blocks addObject:failureBlock];
		[failureBlock release];
		failureBlock = nil;
	}
....
	[[self class] performSelectorOnMainThread:@selector(releaseBlocks:) withObject:blocks waitUntilDone:[NSThread isMainThread]];
}
// Always called on main thread
+ (void)releaseBlocks:(NSArray *)blocks
{
	// Blocks will be released when this method exits
}
#endif

疑问:
1.blocks变量应该在主线程被释放还是releaseBlocksOnMainThread所在线程?有文档能证明么?
2.releaseBlocks为什么里面什么都不干呢?

另外:我测试解决4.3.3的blockcrash问题就是改掉

+ (void)releaseBlocks:(NSMutableArray *)blocks
{
	// Blocks will be released when this method exits
    [blocks removeAllObjects];//解决4.3.3子线程释放block的bug

}
不知道这样做是否合理, 如果是合理的为什么作者不这样做呢?

PHP中文网
PHP中文网

认证高级PHP讲师

全部回覆(1)
Peter_Zhu

首先,你改了這個方法原理上並不能解決blocks變數被過度釋放的問題,因為你只是對blocks這數組的元素做了操作。
另,回答你兩個問題:
1,blocks變數一定是在主執行緒釋放的,就是避免多執行緒並發時的衝突,所以才會

[[self class] performSelectorOnMainThread:@selector(releaseBlocks:) withObject:blocks waitUntilDone:[NSThread isMainThread]];

2,我還真沒想到為什麼他是空的,我再研究一下~~~

另外,建議你把創建請求,處理block的程式碼都貼上來,因為現在看現像我覺得是你處理Block的時候有問題,不是ASI的問題

補充

高人點解,弄清楚為什麼這個方法是空的了。因為blocks是作為參數傳給releaseBlocks:的,所以引用計數會+1,當函數執行結束,blocks引用計數-1,所以被釋放

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板