在超视图之后,MKMapView仍然将消息发送给委托

编辑:改变了标题。 我当时不知道,但是这是一个重复的为什么我崩溃后MKMapView被释放,如果我不再使用它?


这个问题与使用ARC + NSZombieEnabled时为什么不释放对象类似,但是我认为值得抛出,以防万一有人理解,可以向我解释发生了什么。 另一个问题可能是一个XCode错误,所以我认为这可能是类似的。

场景:

  1. RootViewController有一个显示一堆项目的tableView
  2. select一个单元格呈现一个模式detailViewController包含另一个tableView
  3. detailViewController其中一个表格单元格包含显示该项目位置的MKMapView
  4. mapView.delegate = detailViewController
  5. closures模式detailViewController

不久之后,应用程序崩溃b / c的MKMapView发送mapView:viewForAnnotation:到现在dealloc'ed detailViewController 。 这个崩溃重新在用户设备上进行临时分发构build,所以这个问题与NSZombieEnabled无关。

我能够通过添加以下内容来解决崩溃问题:

 _mapView.delegate = nil; 

到包含mapView的tableViewCelldealloc方法。

问题:当cell被释放时,为什么需要删除这个代表呢? 看起来像mapView应该被ARC释放,当细胞被释放时,这是不必要的。 这是一个很好的做法,可以让代表无效,但是我不认为在这种情况下是必须的。

编辑: detailViewControllerUITableViewCells所有子视图声明为(nonatomic, strong)属性ala:

 @property (nonatomic, strong) MKMapView * mapView; 

编辑2:猜猜我需要更好地阅读文档。 @fluchtpunkt是正确的。 以下是MKMapView文档中的相关信息:

在释放已设置委托的MKMapView对象之前,请记住将该对象的委托属性设置为nil。 一个你可以做的地方是在你处理地图视图的dealloc方法中。

MKMapView没有用ARC编译,因此delegate的属性仍然被声明为assign而不是weak
从MKMapView文档 :

 @property(nonatomic, assign) id<MKMapViewDelegate> delegate 

从过渡到ARC发行说明 :

如果您需要pipe理资源,而不是释放实例variables,则可以实施dealloc方法。 您不必(实际上不能)释放实例variables,但是您可能需要在系统类和其他未使用ARC编译的代码上调用[systemClassInstance setDelegate:nil]


对于系统类(NS *,UI *)的委托,当您释放委托对象时,必须使用设置委托的“旧”规则为nil。

所以添加一个dealloc方法到你的detailViewController

 - (void)dealloc { self.mapView.delegate = nil; } 

虽然这样的类的代表应该被明确地设置nil ,但是在dealloc这样做已经太晚了。 在viewDidUnload期间,您已经失去了对mapview的引用。 你应该做的self.mapView.delegate = nil BEFORE的viewDidUnload (所以可能viewWillDisappearviewDidDisappear

根据我的经验,只有MKMapViewUIWebView行为是这样的。