This fixed an issue for me where gradle couldn't build the iOS framework for my Kotlin Multiplatform Mobile app.
Post
Replies
Boosts
Views
Activity
I think this may be related to a problem I've been having. A GeometryReader inside a .background or .overlay never runs/updates its children on a real device or simulator, but does work correctly in previews. I tried your suggestion of adding an AnyView and that made it work on the simulator and real phone. FWIW I made a simple demo of the bug. Without the AnyView(), on a real device or simulator the first Text stays stuck on "Square size unknown", but the second does update to "Did run updater: true".
Usually one should use .onAppear and/or .onChange(of:) to alter state, but they do not work in this context regardless of whether I use the AnyView hack. I've tried them in the GeometryUpdater, outside and inside the AnyView, and also in UpdateStateDuringViewUpdate. They never get called. This bug affects previews too.
import SwiftUI
struct UpdateStateDuringViewUpdate<T>: View {
init(_ stateBinding: Binding<T>, _ newValue: T) {
DispatchQueue.main.async {
stateBinding.wrappedValue = newValue
}
}
var body: some View { EmptyView() }
}
struct TestGeomReader: View {
@State var squareSize = "unknown"
@State var didRunUpdater = "false"
var body: some View {
VStack(alignment: .center) {
GreySquare()
.background {
GeometryUpdater(updatingStringWithSize: $squareSize)
}
Text("Square size \(squareSize)")
Text("Did run updater: \(didRunUpdater)")
}
}
@ViewBuilder func GreySquare() -> some View {
Rectangle()
.fill(Color(fromARGB: 0x80808080))
.frame(maxWidth: 200, maxHeight: 200, alignment: .center)
}
@ViewBuilder func GeometryUpdater(
updatingStringWithSize binding: Binding<String>
) -> some View {
UpdateStateDuringViewUpdate($didRunUpdater, "true")
GeometryReader { geom in
AnyView(UpdateStateDuringViewUpdate($squareSize, "\(geom.size.width)"))
}
}
}
struct TestGeomReader_Previews: PreviewProvider {
static var previews: some View {
TestGeomReader()
}
}
I've got the same problem. Like the OP found, MapMarker is OK, MapAnnotation isn't, no matter how simple (even with nothing but an EmptyView). Also, if I click on one of the purple triangles XCode claims it's caused by the @main annotation before my App definition.
I've tried eliminating all @State vars from my View, and wrapped my MKCoordinateRegion in a simple class to make it mutable, and passed a simple binding to the Map constructor:
Binding(
get: {coordinateRegionHolder.coordinateRegion},
set: { region in
self.coordinateRegionHolder.coordinateRegion = region
})
I'm still getting those error messages. I think something in MapAnnotation is incorrectly modifying some internal state during update, because it seems less likely to me that XCode would misdetect it if it isn't happening. We're not supposed to make our own custom annotations by implementing MapAnnotationProtocol (why not?), so it looks like UIViewRepresentable is the only way we can be confident of reliably displaying a map with custom annotations.
Answering my own question, I later found out about @MainActor, which seems to be just what I need.
I've found out it was because the PNG had a very high ppi setting of almost 300, instead of the usual 72. Bundle.image(forResource:) has the same bug. Yes, this is a bug. Even if you consider that ppi applies to the screen as well as to print, the scaling should be deferred to render time rather than as soon as it's loaded (throwing away over 94% of the detail!).