SwiftUI is still at the beginning of his road. When you remember Swift 1.2 or Swift 2.0 you probably know what I mean. There is still something missing.

One of the base View which is missing in SwiftUI is MKMapView. Now, let’s go fix it with UIViewRepresentable.

The first solution can look like this:

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {

	@Binding var annotations: [MKAnnotation]

	// MARK: - UIViewRepresentable
	typealias UIViewType = MKMapView

	func makeUIView(context: UIViewRepresentableContext<MapView>) -> MapView.UIViewType {
		return MKMapView()
	}

	func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
		uiView.removeAnnotations(uiView.annotations)
		uiView.addAnnotations(annotations)
	}
}

However, in this solution, all annotation should implement MKAnnotation which means everyone pin will inherit from NSObject and import MapKit

So let’s now go fix this with new MapAnnotation protocol.

protocol MapAnnotation {
	/// The center point (specified as a map coordinate) of the annotation.
	var coordinate: CLLocationCoordinate2D { get }
	/// The string containing the annotation’s title.
	var title: String? { get }
	/// The string containing the annotation’s subtitle.
	var subtitle: String? { get }
}

extension MapAnnotation {
	var title: String? { nil }
	var subtitle: String? { nil }
}

And update MapView to accept MapAnnotation protocol with MKAnnotationWrapper helper class.

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {

	@Binding var annotations: [MapAnnotation]

	// MARK: - UIViewRepresentable
	typealias UIViewType = MKMapView

	func makeUIView(context: UIViewRepresentableContext<MapView>) -> MapView.UIViewType {
		return MKMapView()
	}

	func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
		uiView.removeAnnotations(uiView.annotations)
		uiView.addAnnotations(annotations.map(MKAnnotationWrapper.init(annotation:)))
	}
}

/// Enable remove `NSObject` and `MKAnnotation` depedencies from `MapView` annotations.
private final class MKAnnotationWrapper: NSObject, MKAnnotation {
	/// The center point (specified as a map coordinate) of the annotation.
	var coordinate: CLLocationCoordinate2D { annotation.coordinate }
	/// The string containing the annotation’s title.
	var title: String? { annotation.title }
	/// The string containing the annotation’s subtitle.
	var subtitle: String? { annotation.subtitle }

	var annotation: MapAnnotation

	init(annotation: MapAnnotation) {
		self.annotation = annotation
	}
}

Finally, our implementation will look more Swift and is independent of NSObject, import MapKit and UIKit. This solution works perfectly on a real device or simulator only in Preview shows like empty view.

struct Prague {
    let title = "Prague"
}

extension Prague: MapAnnotation {
    var coordinate: CLLocationCoordinate2D { .init(latitude: 50.08804, longitude: 14.42076) }
}

struct SampleView: View {
    var body: some View {
        MapView(annotations: .constant([Prague()]))
    }
}

MapView on iPhone simulator

Look at final MapView implementation or on more other UIKit views implemented to SwiftUI.