A有一个视图控制器,它创建一个“下载器”对象,它有一个对视图控制器的引用(作为委托)。如果成功下载项目,下载程序将回调视图控制器。只要您保持在视图中,这样就可以正常工作,但如果您在下载完成之前离开,我会得到EXC_BAD_ACCESS
。我理解为什么会发生这种情况,但有没有办法检查对象是否仍然被分配?
我尝试使用delegate != nil
和[delegate respondsToSelector:]
进行测试,但它会窒息。
if (!self.delegate || ![self.delegate respondsToSelector:@selector(downloadComplete:)]) {
// delegate is gone, go away quietly
[self autorelease];
return;
}
else {
// delegate is still around
[self.delegate downloadComplete:result];
}
我知道我可以,
a)让下载程序对象保留视图控制器
b)在视图控制器中保留一组下载程序,并在取消分配视图控制器时将其委托值设置为nil。
但是我想知道是否有更简单的方法,我只测试代理地址是否包含有效对象?
答案 0 :(得分:27)
我刚遇到这个问题并解决了它。对于ARC,解决方案是使用weak
属性而不是assign
。
崩溃是因为代表
assign
属性,AND 解决方案是使用weak
属性,因为当对象解除分配时,指针将设置为nil
。因此,当您的代码在respondsToSelector
上调用nil
时,Objective C将忽略该调用,而不会崩溃。
在您的代码中,当您尝试在respondsToSelector
上调用delegate
方法时,您会获得EXC_BAD_ACCESS。这是因为使用assign
属性的对象在取消分配时不会设置为nil
。 (因此,为什么在!self.delegate
之前执行respondsToSelector
不会阻止在解除分配的对象上调用responseToSelector
,并且仍然会使代码崩溃)
如前所述,在ARC中使用委托上的strong
或assign
属性(正如许多人所提到的)将导致保留周期。所以不要这样做,你不需要。
答案 1 :(得分:10)
不,你不能(有用)“测试地址是否包含有效对象”。即使您能够在内存分配系统的内部进行内容并确定您的地址指向有效对象,这也不一定意味着它是您之前引用的相同的对象to:对象可能已被释放,另一个对象在同一个内存地址创建。
保留代表是解决此问题的常用方法。您的选项(b)打破了对象封装,可能存在线程安全问题。
答案 2 :(得分:1)
我会写
SEL slc = @selector(theSlc);
if ([delegate respondsToSelector:slc]) {
[delegate performSelector:slc];
}
如果对象有效,则调用该方法,否则不调用。您无需检查
self.delegate != nil
答案 3 :(得分:1)
我遇到了这个问题,因为我的“下载程序”对象给了我EXC_BAD_ACCESS。我的解决方案是在我发布它之前取消下载器对象。假设您在下载程序对象中使用NSURLConnection,请在其上调用cancel方法。
重要的是要注意,如果NSURLConnection当前没有下载任何内容,那么调用cancel将导致崩溃。您需要一些逻辑来检查下载是否正在进行中。
答案 4 :(得分:1)
我也有委托弱引用的问题,目前我只有一个解决这个问题的方法:使用强引用委托,并手动设置self.delegate = nil;我的代码完成后。这个解决方案适用于异步图像加载,你有一些生命周期可见的结束。