MKMapView still sending messages to delegate after it's superview has been de-alloc'ed

流过昼夜 提交于 2019-12-21 07:35:21

问题


EDIT: changed the title. I didn't know it at the time but this is a duplicate of Why am I crashing after MKMapView is freed if I'm no longer using it?


This question is similar to Why is object not dealloc'ed when using ARC + NSZombieEnabled but different enough that I thought it worth throwing out there in case anyone understands and can explain to me what is happening. The other question may be an XCode bug so I presume this could be similar.

Scenario:

  1. RootViewController has a tableView displaying a bunch of items
  2. Selecting a cell presents a modal detailViewController containing another tableView
  3. One of the table cells in detailViewController contains an MKMapView showing the location of the item
  4. mapView.delegate = detailViewController
  5. Dismiss the modal detailViewController

Soon after this, the app crashes b/c the MKMapView sends mapView:viewForAnnotation: to the now dealloc'ed detailViewController. This crash repro'ed on a users device with an ad-hoc distribution build so the issue has nothing to do with NSZombieEnabled.

I was able to resolve the crash by adding:

_mapView.delegate = nil;

to the dealloc method of the tableViewCell containing the mapView.

QUESTION: why is it necessary to nil the delegate when the cell is dealloc'ed? It seems like the mapView should be dealloc'ed by ARC when the cell is dealloc'ed leaving this unnecessary. It is good practice to nil delegates but I didn't think it would be required in this case.

EDIT: all subviews of both detailViewController and the UITableViewCells are declared as (nonatomic, strong) properties ala:

@property (nonatomic, strong)   MKMapView *         mapView;

EDIT 2: Guess I need to get better at reading the docs. @fluchtpunkt is correct. Here's the relevant info from the MKMapView documentation:

Before releasing an MKMapView object for which you have set a delegate, remember to set that object’s delegate property to nil. One place you can do this is in the dealloc method where you dispose of the map view.


回答1:


MKMapView is not compiled with ARC and because of that the property for delegate is still declared as assign instead of weak.
From the MKMapView documentation:

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

And from the Transitioning to ARC Release Notes:

You may implement a dealloc method if you need to manage resources other than releasing instance variables. You do not have to (indeed you cannot) release instance variables, but you may need to invoke [systemClassInstance setDelegate:nil] on system classes and other code that isn’t compiled using ARC.


For delegates of system classes (NS*, UI*) you have to use the "old" rule of setting delegates to nil when you deallocate the delegate object.

so add a dealloc method to your detailViewController

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



回答2:


While it's true that the delegates for such classes should be explicitly set to nil, doing it in dealloc is already too late. You already lost your reference to the mapview during viewDidUnload. You should do the self.mapView.delegate = nil BEFORE viewDidUnload (so probably viewWillDisappear or viewDidDisappear)

From my experience, only MKMapView and UIWebView behave this way.



来源:https://stackoverflow.com/questions/8568966/mkmapview-still-sending-messages-to-delegate-after-its-superview-has-been-de-al

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