【问题标题】:Avoiding EXC_BAD_ACCESS when using the delegate pattern使用委托模式时避免 EXC_BAD_ACCESS
【发布时间】:2011-02-10 10:20:34
【问题描述】:

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。

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

【问题讨论】:

  • 如果你可以测试一个地址是否包含一个有效的对象,根据定义,它会,因为访问它来测试它是有效的?
  • objective-c 有很多抽象......我可以想象这样一个世界,运行时能够区分具有有效对象的地址和已释放对象的地址。

标签: iphone objective-c memory-management exc-bad-access


【解决方案1】:

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

崩溃是因为委托

  1. 有一个assign 属性,并且
  2. 已解除分配。

解决方案是使用weak 属性,因为当对象释放时,指针设置为nil。因此,当您的代码在 nil 上调用 respondsToSelector 时,Objective C 将忽略该调用,并且不会崩溃。

在您的代码中,当您尝试在 delegate 上调用 respondsToSelector 方法时,您会得到一个 EXC_BAD_ACCESS。这是因为使用assign 属性的对象在被释放时不会设置为nil。 (因此为什么在respondsToSelector 之前执行!self.delegate 不会阻止responseToSelector 被释放的对象调用,并且仍然会使您的代码崩溃)

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

【讨论】:

  • 除了使用weak,还有其他需要吗?例如,主类中的“delegate = nil”或设置“id _strong delegate”?我假设我遇到了同样的问题stackoverflow.com/questions/24466244/…
  • 您不需要做任何其他事情。我阅读了您的问题,并注意到您提供的回复表明使用 weak 而不是 assign 修复了崩溃。您还遇到问题吗?
  • 谢谢......你的回答拯救了我的一天@DrewH
  • 很好的解释,但是我也面临着弱代表的问题。
  • 谢谢,一切正常! if (self.delegate && [(NSObject*)self.delegate respondsToSelector:@selector(customMethod:clickedButton:)]) { [delegate customMethod:self clickedButton:[sender tag]]; } 带有 weak 属性删除
【解决方案2】:

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

保留委托是解决此问题的常用方法。您的选项 (b) 破坏了对象封装,并且可能存在线程安全问题。

【讨论】:

  • 我可以看到的大多数苹果实现都没有保留委托......例如@property(nonatomic,assign) id <UITableViewDelegate> delegate;我是不是误用了设计模式?
  • 这对于需要所有交互都在主线程上发生的 UI 对象来说可能是正确的,但我认为您会发现在后台线程中执行异步操作的实现(例如 NSURLConnection)将保留他们的代表。
  • 永远不会保留代表!仅保留目标
  • 您能否解释更多或提供参考,@eaigner。我用谷歌搜索了一下,找不到目标的定义。
  • @eaigner 关于代表永远不会被保留的说法,您的参考是什么?例如,NSURLConnection 方法-initWithRequest:delegate:确实保留了委托(并且记录在案)。
【解决方案3】:

我只想写

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

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

self.delegate != nil

【讨论】:

  • 你可能是对的,我的!self.delegate 是多余的。但是,我知道[delegate respondsToSelector:] 并不能保护您免受EXC_BAD_ACCESS 的侵害。尝试运行: NSObject *obj = [[NSObject alloc] init]; [对象释放]; for (int i = 0; i
【解决方案4】:

我遇到这个问题是因为我的“下载器”对象给了我 EXC_BAD_ACCESS。我的解决方案是在我发布之前取消下载器对象。假设您在下载器对象中使用 NSURLConnection,请在其上调用 cancel 方法。

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

【讨论】:

    【解决方案5】:

    我也遇到了delegate弱引用的问题,目前我只有一个解决方案:对delegate使用强引用,手动设置self.delegate = nil;我的代码完成后。此解决方案适用于异步图像加载,您有一些生命周期可见结束。

    【讨论】:

      猜你喜欢
      • 2012-05-04
      • 1970-01-01
      • 2014-11-30
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 1970-01-01
      • 2022-01-14
      • 2015-11-18
      相关资源
      最近更新 更多