10

I'm trying to create a default implementation of an MKMapViewDelegate by using the conditional extension as follows:

extension MKMapViewDelegate where Self: NSObject {
        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            ...
        }

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

However when I compile the code i get the warning

Non-'@objc' method 'mapView(_:viewFor:)' does not satisfy optional requirement of '@objc' protocol 'MKMapViewDelegate'

I expected the conformance on 'Self' to NSObject would mean that the warning would not occur. On top of the warning the delegate methods are not called even though the delegate instance is a UIViewController and hence conforms to NSObject.

Am I misunderstanding how 'where' works in extensions?

  • 1
    Possible duplicate of [Non-'@objc' method does not satisfy optional requirement of '@objc' protocol](http://stackoverflow.com/questions/39487168/non-objc-method-does-not-satisfy-optional-requirement-of-objc-protocol) – Richard Venable Sep 29 '16 at 18:34

1 Answers1

0

NSObject will no longer infer @objc as of Swift 4 due to the acceptance of Doug Gregor's proposal: SE-0160.

I admit I have not put in the time to understand the reason behind your error though. I have merely posted this answer in hopes that anybody else reading your question will see the following advice.

It is bad practice, or 'code smell', to provide a default implementation to a protocol for your entire module. I would recommend an alternative approach wherein you create a custom type such as MapViewDelegate with some default behaviour that can be shared amongst types that explicitly conform to that protocol.

For example:

import MapKit
protocol MapViewDelegate: MKMapViewDelegate {}
extension MapViewDelegate where Self: NSObject {
    func annotationView(for annotation: MKAnnotation, in mapView: MKMapView) -> MKAnnotationView? {
        …
    }

    func renderer(for overlay: MKOverlay, in mapView: MKMapView) -> MKOverlayRenderer {
        …
    }
}
final class MyMapDelegate: NSObject, MapViewDelegate {
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        return annotationView(for: annotation, in: mapView)
    }
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        return renderer(for: overlay, in: mapView)
    }
}
Infinity James
  • 4,667
  • 5
  • 23
  • 36
  • While this is a functional solution it does not actually answer the question. The question was why the conformance to NSObject does not get rid of the warnings. – Mattias Bowallius May 22 '17 at 06:50