I have a .task( id: geometryEditor.geometry ) on my MapView (I have tried .onChange( of: ) and it behaves the same). It triggers on geometryEditor.start() or .stop(), but it doesn't trigger on any interactive edits (adding/moving points, etc.)
I'm attempting to use the GeometryEditor as a convenient way to measure along a polyline or the area or edges of a polygon, so I really just need to update a Text() view after doing a few calculations on the current .geometry whenever it changes. Am I missing something obvious? Is there something more I need to do than to add a .task or .onChange with the .geometry to observe?
Thanks!
-Dave
Solved! Go to Solution.
Thanks for asking this question! The geometry property is a "Streamed" property, which means its projected value (accessed with the dollar sign) is an asynchronous stream. In order to get updates from the stream, the new Swift Concurrency for-await-in syntax needs to be used.
Consider the snippet below. Whenever the geometry of the geometryEditor changes, the async stream will give an update.
If you aren't familiar with this topic, I recommend reading this blog (by me 😉) to get familiar with the gist of Swift Concurrency in ArcGIS Maps SDK.
Happy holidays!
import SwiftUI
import ArcGIS
struct ContentView: View {
private class Model: ObservableObject {
let map = Map(basemapStyle: .arcGISTopographic)
let geometryEditor: GeometryEditor = {
let editor = GeometryEditor()
editor.tool = VertexTool()
return editor
}()
}
@StateObject private var model = Model()
var body: some View {
MapView(map: model.map)
.geometryEditor(model.geometryEditor)
.task {
for await geometry in model.geometryEditor.$geometry {
print("Geometry \(geometry?.extent) Changed")
}
}
.onAppear {
model.geometryEditor.start(withType: Polyline.self)
}
}
}
Thanks for asking this question! The geometry property is a "Streamed" property, which means its projected value (accessed with the dollar sign) is an asynchronous stream. In order to get updates from the stream, the new Swift Concurrency for-await-in syntax needs to be used.
Consider the snippet below. Whenever the geometry of the geometryEditor changes, the async stream will give an update.
If you aren't familiar with this topic, I recommend reading this blog (by me 😉) to get familiar with the gist of Swift Concurrency in ArcGIS Maps SDK.
Happy holidays!
import SwiftUI
import ArcGIS
struct ContentView: View {
private class Model: ObservableObject {
let map = Map(basemapStyle: .arcGISTopographic)
let geometryEditor: GeometryEditor = {
let editor = GeometryEditor()
editor.tool = VertexTool()
return editor
}()
}
@StateObject private var model = Model()
var body: some View {
MapView(map: model.map)
.geometryEditor(model.geometryEditor)
.task {
for await geometry in model.geometryEditor.$geometry {
print("Geometry \(geometry?.extent) Changed")
}
}
.onAppear {
model.geometryEditor.start(withType: Polyline.self)
}
}
}
I appreciate the help, the for/await was what I needed. This is my first, and hopefully last Swift project. I guess I'm just a dinosaur now and my 35 years of experience in the various flavors of C no longer translates to these hipster languages.