1

Anyone able to spot why when I set the "firstPass" state variable in the "updateUIView" callback it does NOT set the state? As output I see:

First Pass1:  true
First Pass2:  true. // <= not set to false as expected

Also I do not in Xcode where I set this state "firstPass = false" that there is an Xcode warning here: "Modifying state during view update, this will cause undefined behavior."

import SwiftUI
import MapKit

struct GCMapView {
    @State var firstPass : Bool = true
   
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: GCMapView
        init(_ parent: GCMapView) {
            self.parent = parent
            super.init()
        }
    }
}

extension GCMapView : UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        let map = MKMapView()
        map.delegate = context.coordinator
        map.showsUserLocation = true
        return map
    }

    func updateUIView(_ view: MKMapView, context: Context) {
        print("--- updateUIView ---")
        if firstPass {
            print("First Pass1: ", firstPass)
            firstPass = false.      // <<=== *** THIS DOES NOT WORK ****
            print("First Pass2: ", firstPass)
        } else {
            print("Subsequent Passes")
        }
    }
}
Greg
  • 34,042
  • 79
  • 253
  • 454

1 Answers1

1

This operation causes cycling, because it invalidates SwiftUI view that result in calling updateUIView and so forth, so SwiftUI rendering engine drops it (auto-fix).

Not really sure you need such if there at all, but possible solution would be to separate update on next event loop, like

if firstPass {
    print("First Pass1: ", firstPass)
    DispatchQueue.main.async {
       firstPass = false
       print("First Pass2: ", firstPass)
    }
} else {

Tested with Xcode 13 / iOS 15

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • thanks heaps - so this is the only way to handle this I guess then? I want to setup on the map a new view point (Rect & centre position) the first time through, then subsequent times not to move it so the user can scroll. I have to use the co-ordinator pattern approach with SwiftUI so the updateUIView callback comes here for the delegate. So there doesn't seem to be another way to update @ State so to speak do you think? You need to use a struct (not class) for "struct GCMapView" it seems, so couldn't think of another way around but using a @ State variable in the struct here – Greg Sep 14 '21 at 20:50