Reputation: 117
How is my MapView "annotations" variable get updated every time I change my "locations" variable in my ContentView? I googled that swift array is a value type, and I don't even need to use binding on the "annotations" and bind to the "locations" for "annotations" get to know when "locations" changes, why is that?
import SwiftUI
import MapKit
struct ContentView: View {
@State var centerCoordinate = CLLocationCoordinate2D()
@State var locations = [MKPointAnnotation]()
var body: some View {
ZStack{
MapView(centerCoordinate: $centerCoordinate, annotations: locations)
Circle()
.fill(Color.blue)
.opacity(0.5)
.frame(width: 32, height: 32, alignment: .center)
VStack{
Spacer()
HStack{
Spacer()
Button(action: {
let newLocation = MKPointAnnotation()
newLocation.coordinate = centerCoordinate
locations.append(newLocation)
}){
Image(systemName: "plus")
}
.padding()
.background(Color.black.opacity(0.75))
.foregroundColor(.white)
.font(.title)
.clipShape(Circle())
.padding([.trailing, .bottom])
}
}
}
.edgesIgnoringSafeArea(.all)
}
}
struct MapView: UIViewRepresentable{
@Binding var centerCoordinate: CLLocationCoordinate2D
var annotations: [MKPointAnnotation]
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.delegate = context.coordinator
return mapView
}
// Callback function - when anything being sent to UIViewRepresentabel struct is changed
func updateUIView(_ uiView: UIViewType, context: Context) {
print("Updating UIView")
if annotations.count != uiView.annotations.count{
uiView.removeAnnotations(uiView.annotations)
uiView.addAnnotations(annotations)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate {
let parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
parent.centerCoordinate = mapView.centerCoordinate
}
}
}
extension MKPointAnnotation{
static var example: MKPointAnnotation{
let point = MKPointAnnotation()
point.coordinate = CLLocationCoordinate2D(latitude: 51.5, longitude: -0.13)
point.title = "London"
point.subtitle = "The home of 2012 Summer Olympics"
return point
}
}
Upvotes: 0
Views: 70
Reputation: 2269
Not sure if I understood your question but let me try.
First you have this state in your View:
@State var locations = [MKPointAnnotation]()
Next, you assign its value to:
MapView(centerCoordinate: $centerCoordinate, annotations: locations)
This means, every time you change locations
, SwiftUI will re-render the MapView
with new values.
Any UIViewRepresentable
have to implement the func updateUIView
in order to receive these changes when SwiftUI re-render the respective component.
So, every time your MapView
being rendered, this function is going to be trigged:
func updateUIView(_ uiView: UIViewType, context: Context) {
print("Updating UIView")
if annotations.count != uiView.annotations.count{
uiView.removeAnnotations(uiView.annotations)
uiView.addAnnotations(annotations)
}
}
The uiView.annotations
and annotations
are note related each other. At the moment uiView.annotations
changes, it just make side effects in the view itself and don't update the given @State
because it could create an infinity rendering loop.
Upvotes: 1