2010-04-21 50 views
17

A有一个视图控制器,它创建一个“下载器”对象,它具有对视图控制器的引用(作为委托)。如果下载器成功下载该项目,则回调视图控制器。只要你停留在视图上,这工作正常,但如果你在下载完成之前离开,我会得到EXC_BAD_ACCESS。我明白为什么会发生这种情况,但有什么方法可以检查一个对象是否仍然被分配? 我试图用delegate != nil[delegate respondsToSelector:]进行测试,但它呛了。使用委托模式时避免EXC_BAD_ACCESS

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]; 
} 

我知道我可以,

一个)已下载器对象保留视图控制器

b)中保持在视图控制器下载程序的阵列,并且设置它们的代表值,以零时我取消分配视图控制器。

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

+0

如果你可以测试一个地址是否包含一个有效的对象,根据定义,它会,因为它是有效的访问它来测试? – 2010-04-21 03:46:46

+1

objective-c有很多抽象...我可以想象一个世界,运行时能够分辨出一个地址与一个有效对象之间的区别,以及一个被释放的地址。 – 2010-04-21 04:22:28

回答

10

不,您不能(有用地)“测试地址是否包含有效的对象”。即使你能够在内存分配系统的内部进行修改,并确定你的地址指向了一个有效的对象,这并不一定意味着它是你之前所指的对象:对象可能已经被释放,另一个对象在相同的内存地址创建。

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

+0

我可以看到苹果的大部分实现不会保留代表... '@property(nonatomic,assign)id delegate;'我错误地应用了设计模式? – 2010-04-21 04:15:08

+0

对于需要在主线程中发生所有交互的UI对象,这可能是正确的,但我认为您会发现在后台线程(如NSURLConnection)中执行异步操作的实现将保留其委托。 – 2010-04-21 04:32:58

+6

A **代表**从未保留!只保留**目标**。 – 2010-04-22 11:37:43

1

我只想写

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

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

self.delegate != nil 
+4

你可能是对的,我的'!self.delegate'是多余的。但是,我确实知道'[delegate respondsToSelector:]'不能保护您免受'EXC_BAD_ACCESS'的攻击。 试试这个: \t NSObject * obj = [[NSObject alloc] init]; \t [obj release];对于(int i = 0; i <2; i ++){ \t if([objrespondsToSelector:@selector(retainCount)]))NSLog(@“retain count:%i”,[obj retainCount]); \t} – 2010-04-23 22:46:48

1

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

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

1

我也有代表弱引用的问题,目前我只有一个解决方案,这个问题:使用强参考委托,并手动设置self.delegate =零;我的代码完成后。这种解决方案适用于异步图像加载,在这里你有一些生命周期可见的结局。

27

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

崩溃而来,是因委托

  1. 有一个assign属性,
  2. 已释放。

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

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

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

+0

除了使用弱点,还有其他的东西需要吗?例如,在主类中设置'delegate = nil'或设置'id _strong delegate'?我假设我遇到同样的问题http://stackoverflow.com/questions/24466244/delegate-dont-exist-exc-bad-access/24970685#24970685 – Hexark 2014-07-26 12:51:41

+2

你不应该做任何事情。我读了你的问题,并注意到你提供了一个响应,指出使用'weak'而不是'assign'来修复崩溃。你还在遇到问题吗? – 2014-07-29 04:59:05

+0

似乎已经解决了问题:) – Hexark 2014-07-31 05:15:21