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

# はじめに

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

```swift
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` を表示するコントローラクラスが複数存在し、それらを抽象化した親クラス `BaseMapViewController` が `MKMapViewDelegate` を宣言していました。（宣言のみで実装は無し）

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

    // MKMapViewDelegateの実装はなし
}
```

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

```swift
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()
    }
}
```

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

# 回避策

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

```swift
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()
    }
}
```