20

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。

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

4

5 回答 5

29

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

崩溃是因为代表

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

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

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

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

于 2014-06-07T19:29:22.363 回答
10

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

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

于 2010-04-21T03:52:35.063 回答
1

我只想写

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

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

self.delegate != nil
于 2010-04-22T11:33:05.557 回答
1

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

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

于 2011-10-24T21:41:47.653 回答
1

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

于 2013-07-24T12:07:28.813 回答