2012년 7월 17일 화요일

MKMapView를 사용하는 앱이 자주 죽는 경우...

맵뷰(MKMapView)를 사용한 앱이 자꾸 죽는 문제가 있었다. 에러의 원인은 sent message to deallocated object, 즉 메모리 상에서 해제되어 버린 오브젝트의 무언가를 호출하려 했기 때문에 죽는다는 것이었다.

이 문제를 잡기 위해 별의별 삽질을 다 해 봤다. 왠만한 곳에서 전부 self의 주소를 로그를 남기도록 해 놓고 테스트를 해 봐도, 죽기 전 까진 코드 내에서 별도로 호출하는 부분이 없었다.

도데체 문제가 뭐란 말인가!

한참을 고민하다 내린 결론은 내 코드 자체가 문제의 원인인 것 같지는 않다라는 점이었다. 맵뷰 내부에서 뭔가 호출하려 하는데 죽는다는 건 delegate와 연관이 클 것 같았다. 그렇다고 맵뷰 내부를 들여다 볼 수도 없고 난감했다.

그런데 실마리는 결국 공식 문서에서 발견하게 되었다. MKMapViewDelegate 문서의 Overview 부분이다.



하단의 Important 위에 이런 내용이 있다.
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.
정리하자면, MapView를 release 하기 전에 delegate를 nil로 초기화 해 주라는 말이다.

결론이 대충 나온 것 같다. 메모리가 해제된 ViewController에서 사용하던 맵뷰가 딜리게이트에 뭔가를 호출하고 있다는 말이다. 아마도 MKMapView 자체는 공유메모리 형태로 메모리 효율을 높이도록 설계가 되어있나 보다. 그러니 맵뷰 자체가 릴리즈 되었음에도 뭔가 내부적으로 계속 동작하고 있다는 말이다. 그래서 맵뷰를 사용하지 않을 시점에는 delegate를 nil로 만들어 줘야 하는가 보다.

결론은 간단하다. dealloc 내부에 mapView.delegate = nil; 이런 식으로 코드를 넣으면 해결된다는 의미이다. 아 짜증난다 ㅠㅠ

댓글 2개 :

allieus :

오~!!! 그런 거였어?

Seorenn :

allieus// 좀 제한적인 상황에서 나타날 수 있는 문제라... 예를 들자면 맵뷰가 들어있는 뷰의 뷰컨트롤러를 자주 교체하는 케이스에선 나타날 수 있어. 특히 맵 네트워크 로딩과 관련이 깊은 듯...