LoginSignup
3
2

More than 3 years have passed since last update.

ReleaseビルドでMKMapViewDelegateのメソッドが呼び出されなくなった話

Posted at

はじめに

これは、ReleaseビルドしたiOSアプリで MKMapViewDelegate の下記のようなメソッドが呼び出されないことがある現象に遭遇し、腑には落ちないけどなんとか解消したというメモです。

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?

状況

環境

  • Xcode 10.2
  • Swift 5
  • iOS 11 or 12

(Xcode 10.1 + Swift 4.2 のころに、この問題は発生していませんでした)

実装

アプリ内に MKMapView を表示するコントローラクラスが複数存在し、それらを抽象化した親クラス BaseMapViewControllerMKMapViewDelegate を宣言していました。(宣言のみで実装は無し)

class BaseMapViewController: UIViewController, MKMapViewDelegate {
    @IBOutlet weak var mapView: MKMapView!

    // MKMapViewDelegateの実装はなし
}

子クラス FirstMapViewController, SecondMapViewController, ThirdMapViewController... が実際にそれぞれの delegate メソッドを実装していましたが、Releaseビルドにおいて FirstMapViewControllerrendererFor は呼び出されるのに、SecondMapViewControllerrendererFor は呼び出されないという不思議現象。(Debugビルドでは想定通り SecondMapViewController のメソッドも呼び出されていました)

class FirstMapViewController: BaseMapViewController {
    func showOverlay() {
        mapView.addOverlay(overlay, .aboveRoads)
    }

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        // 呼び出される😇
        return FirstRenderer()
    }
}

class SecondMapViewController: BaseMapViewController {
    func showOverlay() {
        mapView.addOverlay(overlay, .aboveRoads)
    }

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        // 呼び出されない❌☠️
        return SecondRenderer()
    }
}

class ThirdMapViewController: BaseMapViewController {
    func showAnnotation() {
        mapView.addAnnotation(annotation)
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
        // 呼び出される😇
        return ThirdView()
    }
}

class FourthMapViewController: BaseMapViewController {
    func showAnnotation() {
        mapView.addAnnotation(annotation)
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
        // 呼び出されない❌☠️
        return FourthView()
    }
}

*もちろん実際の実装はもっと複雑で、このコードだとおそらくちゃんと呼び出されると思うのですが、雰囲気が伝わればということでご了承ください。(なにしろ、実装を変更していないのに、突如呼び出されなくなってしまったので)

回避策

BaseMapViewControllerrendererForviewFor の空実装を定義し、それぞれの子クラスでそれらの delegate メソッドを override すると、リリースビルドでも正しく delegate メソッドが呼ばれるようになりました。

class BaseMapViewController: UIViewController, MKMapViewDelegate {
    @IBOutlet weak var mapView: MKMapView!

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        // 空実装
        return MKOverlayRenderer()
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
        // 空実装
        return nil
    }
}

class FirstMapViewController: BaseMapViewController {
    override func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        // 呼び出される😇
        return FirstRenderer()
    }
}

class SecondMapViewController: BaseMapViewController {
    override func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        // 呼び出された!!⭕️😇
        return SecondRenderer()
    }
}

class ThirdMapViewController: BaseMapViewController {
    override func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
        // 呼び出される😇
        return ThirdView()
    }
}

class FourthMapViewController: BaseMapViewController {
    override func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
        // 呼び出された!!⭕️😇
        return FourthView()
    }
}
3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2