代码之家  ›  专栏  ›  技术社区  ›  Kenny Winker

使用委托模式时避免exc_bad_访问

  •  18
  • Kenny Winker  · 技术社区  · 14 年前

    a有一个视图控制器,它创建一个“downloader”对象,该对象具有对视图控制器的引用(作为委托)。如果下载程序成功下载了该项,则下载程序将回调视图控制器。只要你停留在视图上,这个就可以工作,但是如果你在下载完成之前离开,我会得到 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。

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

    5 回复  |  直到 10 年前
        1
  •  10
  •   David Gelhar    14 年前

    不,您不能(有用地)“测试地址是否包含有效对象”。即使您能够在内存分配系统的内部搜索并确定您的地址指向一个有效的对象,也不一定意味着它是 相同的 以前引用的对象:该对象可能已被释放,并且在同一内存地址创建了另一个对象。

    保留代理是解决此问题的常用方法。您的选项(b)中断了对象封装,并且可能有线程安全问题。

        2
  •  27
  •   Drew H    10 年前

    我刚碰到这个问题就解决了。对于arc,解决方案是使用 weak 属性而不是 assign .

    崩溃是因为代表

    1. 有一个 分配 属性,和
    2. 已解除分配。

    解决方法是使用 虚弱的 属性,因为当对象取消分配时,指针 威尔 被设定 nil . 所以当你的代码调用 respondsToSelector 在一 ,目标C将忽略调用,而不是崩溃。

    在你的代码中,当你试图调用 响应选择器 方法对 delegate ,您将获得一个exc_bad_访问权限。这是因为使用 分配 属性将不设置为 当他们被释放。(因此为什么 !self.delegate 之前 响应选择器 不能阻止 responseToSelector 对已解除分配的对象调用,但仍会导致代码崩溃)

    如前所述,使用 strong 分配 arc中委托(正如许多人所提到的)的属性将导致一个保留周期。所以不要做,你不需要。

        3
  •  1
  •   Era    14 年前

    我只会写信

    SEL slc = @selector(theSlc);
    if ([delegate respondsToSelector:slc]) {
        [delegate performSelector:slc];
    }
    

    如果对象有效,则将调用该方法,否则不调用。你不必检查

    self.delegate != nil
    
        4
  •  1
  •   AlBeebe    13 年前

    我遇到这个问题是因为我的“downloader”对象给了我exc_bad_访问权限。我的解决方案是在释放下载程序对象之前取消它。假设在downloader对象中使用nsurlconnection,则对其调用cancel方法。

    需要注意的是,如果nsurlconnection当前没有下载任何内容,那么调用cancel将导致崩溃。您需要一些逻辑来检查下载是否正在进行。

        5
  •  1
  •   Vitalii Gozhenko    11 年前

    我也有委托弱引用的问题,目前我只有一个解决方案:对委托使用强引用,并在代码完成后手动设置self.delegate=nil。这个解决方案在异步图像加载中对我很有用,在异步图像加载中,有一些生命周期具有可见的结束。