在代表范式中取消分配

时间:2012-07-20 18:49:13

标签: iphone objective-c ios

ParentViewController分配ChildViewController,将其推送到控制器堆栈并释放它。

ChildViewController实现Product类所需的协议ProductDownloadDelegateProtocol

在某些时候,ChildViewController会创建一个Product对象并将其自身设置为downloadDelegate

通过Product中定义的方法下载ChildViewController课程更新ProductDownloadDelegateProtocol

如果用户在下载时按下ChildViewController导航栏中的后退按钮,则下次Product下载百分比更新会导致EXC_BAD_ACCESS

虽然Product会检查downloadDelegate是否为nil,但问题仍然存在,因为ChildViewController/downloadDelegate已取消分配,但未设置为nil。我不知道哪个点最适合ChildViewController设置为nil

我的设计错了吗?

2 个答案:

答案 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进行进度通知。