I want to display an Apple map in my UIKit app, but if I try using UIKit I get concurrency-related warnings (Xcode 15.4 with strict concurrency warnings enabled) that I couldn't find a proper solution to.
So I opted for SwiftUI, and for the iOS 17 approach, specifically, (WWDC23).
The following code displays a map with a marker.
If you look at the Map
initializer, you can see that a map camera position
and a map selection
are specified.
If you run the app, however, you can't actually select the marker, unless you uncomment .tag(mapItem)
.
import SwiftUI
import MapKit
struct MapView: View {
@State private var mapCameraPosition: MapCameraPosition = .automatic
@State private var mapSelection: MKMapItem?
let mapItem = MKMapItem(
placemark: .init(
coordinate: .init(
latitude: 37,
longitude: -122
)
)
)
var body: some View {
Map(
position: $mapCameraPosition,
selection: $mapSelection
) {
Marker(item: mapItem)
// .tag(mapItem)
}
.onChange(of: mapSelection) { _, newSelection in
print("onChange") // never prints
if let _ = newSelection {
print("selected") // never prints
}
}
}
}
If you give another tag, like 1
, the code once again doesn't work.
Is that really the way to go (that is, is my code with fine once you uncomment .tag(mapItem)
)?
If not, how do I make a map with selectable MKMapItem
s in iOS 17?
iOS 17.5, iPhone 15 Pro simulator, Xcode 15.4, macOS 14.5, MacBook Air M1 8GB.
Ok you may as well display markers like this:
ForEach(mapItems, id: \.self) {
Marker(item: $0)
}
where mapItems
is of type [MKMapItem]
.
Complete code:
import SwiftUI
import MapKit
struct MapView: View {
@State private var mapCameraPosition: MapCameraPosition = .automatic
@State private var mapSelection: MKMapItem?
let mapItems = [MKMapItem(
placemark: .init(
coordinate: .init(
latitude: 37,
longitude: -122
)
)
)]
var body: some View {
Map(
position: $mapCameraPosition,
selection: $mapSelection
) {
ForEach(mapItems, id: \.self) {
Marker(item: $0)
}
}
.onChange(of: mapSelection) { _, newSelection in
print("onChange")
if let _ = newSelection {
print("selected")
}
}
}
}