Avoiding EXC_BAD_ACCESS when using the delegate pattern

浪子不回头ぞ 提交于 2019-12-03 05:54:06

No, you can't (usefully) "test if an address contains a valid object". Even if you were able to grub around inside the internals of the memory allocation system and determine that your address points to a valid object, that would not necessarily mean that it was the same object that you were previously referring to: the object could have been deallocated and another object created at the same memory address.

Retaining the delegate is the usual way to solve this. Your option (b) breaks object encapsulation, and might have thread-safety issues.

I just ran into this problem and solved it. For ARC, the solution is to use the weak attribute instead of assign.

The crash come because the delegate

  1. Has an assign attribute, AND
  2. Has been deallocated.

The solution is to use the weak attribute, because when the object deallocates, the pointer WILL be set the nil . So when your code calls respondsToSelector on a nil, Objective C will ignore the call, and not crash.

In your code, when you attempt to call the respondsToSelector method on delegate, you get a EXC_BAD_ACCESS. This is because objects that use the assign property will not be set to nil when they are deallocated. (Hence why doing a !self.delegate before the respondsToSelector does not prevent the responseToSelector from being called on a deallocated object, and still crashes your code)

As already mentioned, using a strong or assign attribute on a delegate (as many have mentioned) in ARC will result in a retain cycle. So don't do it, you don't need to.

I would just write

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

If the object is valid the method will be called, otherwise not. You do not have to check for

self.delegate != nil

I came across this question because my "downloader" object was giving me EXC_BAD_ACCESS. My solution was the cancel the downloader object right before I released it. Assuming your using NSURLConnection in your downloader object, call the cancel method on it.

Its important to note that if NSURLConnection is not currently downloading anything then calling cancel will result in a crash. You will need some logic to check if a download is in progress.

I also have problems with delegate weak reference, and currently I have only one solution for this problem: use strong reference for delegate, and manually set self.delegate = nil; after my code is complete. This solution works for me in async images loading, where you have some life cycle with visible ending.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!