我ParentViewController
分配ChildViewController
,将其推送到控制器堆栈并释放它。
ChildViewController
实现Product类所需的协议ProductDownloadDelegateProtocol
。
在某些时候,ChildViewController
会创建一个Product对象并将其自身设置为downloadDelegate
。
通过Product
中定义的方法下载ChildViewController
课程更新ProductDownloadDelegateProtocol
。
如果用户在下载时按下ChildViewController
导航栏中的后退按钮,则下次Product
下载百分比更新会导致EXC_BAD_ACCESS
。
虽然Product
会检查downloadDelegate
是否为nil
,但问题仍然存在,因为ChildViewController/downloadDelegate
已取消分配,但未设置为nil
。我不知道哪个点最适合ChildViewController
设置为nil
。
我的设计错了吗?
答案 0 :(得分:3)
如果您的ChildViewController
创建了Product
的实例并将自己设置为委托,那么当它将要卸载时,它应该将自己作为委托删除。无论是使用viewDidUnload
还是dealloc
方法,您都应该将Product
委托设置为nil。
如果ChildViewController
停留在周围(假设您正在重复使用视图控制器),也许您可以将其作为viewWillDissappear
方法中的委托将其删除。
修复此特定EXC_BAD_ACCESS问题的另一个解决方案是转移到ARC并使用归零弱引用(请参阅此处的好文章,http://www.mikeash.com/pyblog/friday-qa-2010-07-16-zeroing-weak-references-in-objective-c.html)。
不过,我建议你出于正确的理由转到ARC,而不是解决你面临的这个特殊问题。
答案 1 :(得分:1)
我的经验法则是这样的:你永远不应该成为你不拥有的对象的代表。这里,“拥有”意味着“坚持引用”(在ARC术语中) 。主要的例外是代表保留你和UIApplication.delegate,因为这有点奇怪。
通常我将逻辑捆绑到setter中:
-(void)setProduct:(Product*)p
{
product.delegate = nil;
[product release];
product = [p retain];
product.delegate = self;
}
-(void)dealloc
{
self.product = nil;
}
然而,这种设计的根本问题是“产品下载”只能有一个代表。如果您离开ChildViewController
然后再回到(新实例)它会怎么样?它们是不同的Product
实例,都被下载了吗?
更好的方法可能是拥有管理下载的下载管理器单例(尽管我讨厌单身人士)并使用NSNotification / NSNotificationCenter进行进度通知。