使用委托模式时避免EXC_BAD_ACCESS

Ken*_*ker 18 iphone memory-management exc-bad-access objective-c

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];
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以,

a)让下载器对象保留视图控制器

b)在视图控制器中保留一组下载程序,并在取消分配视图控制器时将其委托值设置为nil.

但我想知道是否有一种更简单的方法,我只测试委托地址是否包含有效对象?

Dre*_*w H 27

我刚遇到这个问题并解决了它.对于ARC,解决方案是使用weak属性而不是assign.

崩溃是因为代表

  1. 有一个assign属性,AND
  2. 已被解除分配.

解决方案是使用weak属性,因为当对象解除分配时,指针 被设置为nil.因此,当您的代码调用respondsToSelectora时nil,Objective C将忽略该调用,而不是崩溃.

在您的代码中,当您尝试调用该respondsToSelector方法时delegate,您将获得EXC_BAD_ACCESS.这是因为在取消分配时,assign不会将使用该属性的对象设置为nil.(因此,为什么在执行!self.delegate之前respondsToSelector不会阻止在responseToSelector解除分配的对象上调用,并且仍然会使代码崩溃)

如前所述,在ARC 中使用委托的一个strongassign属性(正如许多人所提到的)将导致保留周期.所以不要这样做,你不需要.

  • 你不应该做任何其他事情.我读了你的问题,并注意到你提供了一个响应,表明使用`weak`而不是`assign`来修复崩溃.你还遇到问题吗? (2认同)

Dav*_*har 10

不,你不能(有用)"测试地址是否包含有效对象".即使您能够在内存分配系统的内部进行内容并确定您的地址指向有效对象,这也不一定意味着它您之前引用的对象相同:该对象可能已经存在取消分配和在同一内存地址创建的另一个对象.

保留代表是解决这个问题的常用方法.您的选项(b)打破了对象封装,并可能存在线程安全问题.

  • **代表**永远不会被保留!仅保留**目标**. (6认同)
  • @eaigner您对从未保留代表的说法有什么参考?例如,NSURLConnection方法`-initWithRequest:delegate:`*确实*保留委托(并记录这样做). (4认同)
  • 您能否请详细解释或提供参考,@ eaigner.我google了一下,找不到__target__的定义. (2认同)