已解决(我认为):在弹出vc后(在dealloc中)将ASIHTTPRequest委托/ NSOperationQueue委托设置为nil。
在开始之前,this问题类似但不一样。
我的应用程序非常接近发布,但这是整个开发过程中存在的唯一持久性错误。它也是向某人演示应用程序时发生的唯一错误,并且由于此错误导致应用程序终止,因此非常令人尴尬。如果有人能找到解决方案(好的),我会奖励一个体面的奖金。
问题开始:
基本上,当ASIHTTPRequest尝试将requestFinished
选择器调用到一个僵尸对象上时会发生此错误。
从环顾四周看,ASIHTTPRequest在面对向僵尸发送选择器时,会将其发送给不是僵尸的类似对象。我听说让它将选择器发送到它本发送给它的控制器的CALayer是很常见的,而且我也把它发送到我的UINavigationButton !? - 无论如何,这会产生异常。
当ASIHTTPRequest类尝试调用'requestFinished'选择器时,会出现问题:
[queue performSelector:@selector(requestFinished:) withObject:self];
这行代码就是失败的代码 - 让我感到困惑的是为什么?在我链接的问题上,OP表示他们通过从视图控制器调用[self retain]
来修复它。当然那不对吗?
结构
我的ASIHTTPRequest的工作方式是,它们被添加到downloadQueue,(NSOperationQueue),它位于我的app委托中。我的应用程序的结构/样式主要基于this sample code,它使用flickr RSS提要做了类似的事情。
我的应用使用ASIHTTPRequest的部分是一个网络摄像头查看器。它有一个带有桌面视图的导航控制器,可显示三个网络摄像头。这些图像是JPEG,每30秒更新一次到静态文件(在远程服务器上)。此表视图中的单元格是自定义的,每个单元格都加载自己的ASIHTTPRequest。单元格下载各自的图像,并显示它们。
这是我创建的方法,在我的每个单元格上调用:
- (void)loadURL:(NSURL *)url {
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url];
[request setDelegate:self];
[request setDidFinishSelector:@selector(requestDone:)];
[request setDidFailSelector:@selector(requestWentWrong:)];
NSOperationQueue *queue = [[MyAppDelegate sharedAppDelegate] downloadQueue];
[queue addOperation:request];
[spinner startAnimating];
[self addSubview:spinner];
[request release];
}
当选择其中一个单元格时,它会将用户带到详细视图,其中加载了另一个ASIHTTPRequest实例,该实例将下载所选网络摄像头的图像。
如何触发错误
在我的应用程序的正常“平静”使用情况下,它表现良好。在这些视图之间(根网络和详细网络摄像头视图之间)发生快速推送和弹出时,会出现此问题。 最常见的情况是,如果您输入详细视图,进度条开始移动,然后再次弹出到根。这使我相信,因为控制器未激活,当ASIHTTPRequest完成时,并且它试图调用控制器,它失败了。
崩溃日志
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x00000480
Crashed Thread: 0
Thread 0 Crashed:
0 libobjc.A.dylib 0x30183f24 objc_msgSend + 24
1 iCompton 0x0003c4d4 0x1000 + 242900
2 CoreFoundation 0x35ea3f72 -[NSObject(NSObject) performSelector:withObject:] + 18
3 iCompton 0x00029082 0x1000 + 163970
4 CoreFoundation 0x35ea3f72 -[NSObject(NSObject) performSelector:withObject:] + 18
5 Foundation 0x33fd3e66 __NSThreadPerformPerform + 266
6 CoreFoundation 0x35ebc8ca __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 8
7 CoreFoundation 0x35e8cec6 __CFRunLoopDoSources0 + 378
8 CoreFoundation 0x35e8c6f2 __CFRunLoopRun + 258
9 CoreFoundation 0x35e8c504 CFRunLoopRunSpecific + 220
10 CoreFoundation 0x35e8c412 CFRunLoopRunInMode + 54
11 GraphicsServices 0x35261d1c GSEventRunModal + 188
12 UIKit 0x33865574 -[UIApplication _run] + 580
13 UIKit 0x33862550 UIApplicationMain + 964
14 iCompton 0x00002b92 0x1000 + 7058
15 iCompton 0x00002b44 0x1000 + 6980
答案 0 :(得分:6)
最常见的情况是,如果您输入详细视图,进度条开始移动,并再次弹出到根目录。这让我相信,因为控制器不活动,当ASIHTTPRequest完成,并且它试图调用控制器时,它会失败。
我认为你是正确的。
当您弹出到根控制器(或任何其他控制器)时,您应该尝试取消ASIHTTPRequest。在取消请求之前,您应将其delegate
设置为nil;或者你可以使用clearDelegatesAndCancel
。
可能这需要您在视图控制器中保留对请求的引用,但这应该没问题。
一个有趣的S.O.关于检测弹出的UIViewController的问题/答案是here。
答案 1 :(得分:0)
你不应该在实时应用程序中使用NSZombieEnabled,内存永远不会被释放。你不需要在开发中关闭它。快速推拉可能会耗尽内存,触发内存警告,并导致事物被释放和释放。在发布崩溃日志之前,我们不会确切知道。
答案 2 :(得分:0)
以下是我解决此问题的方法:在viewController的delegate
方法中将ASIHTTPRequest
的{{1}} nil
设置为dealloc
。
这阻止了杰出的ASIHTTPRequest
在viewController从导航堆栈弹出后didFinishSelector
向viewController上的didFailSelector
,dealloc
等发送消息“d。
请注意:ASIHTTPRequest
方法cancelAllOperations
可能异步调用didFailSelector
。在这种情况下,可以在不再存在的viewController上调用选择器 。