I am working on an app that tracks the user's location and saves some data related to the location in CoreData. I am new to SwiftUI, so my question is related to where/how is the best place in the app to save the location data into CoreData.
Currently, I have a setup that is very similar to the accepted solution here: How to get Current Location using SwiftUI, without ViewControllers?
Therefore I won't repeat the code that is already in the above link but will make references to it. So you may want to take a look at the answer before reading the rest of my problem statement.
So in class LocationManager I have:
@Published var userLocations: [CLLocation]? {
willSet {
objectWillChange.send()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let howOldIsTheLastLocationData = abs(location.timestamp.timeIntervalSinceNow)
if howOldIsTheLastLocationData < 15 && location.horizontalAccuracy > 0 && location.horizontalAccuracy < 15 {
if userLocations == nil {
userLocations = []
}
userLocations?.append(location)
}
print(#function, location, location.latitudeString, location.longitudeString, location.altitude, howOldIsTheLastLocationData)
}
Therefore userLocations is what I would like to observe in my View and also save into my CoreData.
Now in my View I have:
@Environment(\.managedObjectContext) var context
@State var segment: Segment?
@ObservedObject var locationManager = LocationManager()
var userPath: [CLLocationCoordinate2D]? {
if let userLocations = locationManager.userLocations {
return userLocations.map( { $0.coordinate })
}
return nil
}
var body: some View {
// A MapView Uses userPath to show the path on a MKMapView
MapView(pathCoordinates: userPath ?? [])
// There is a button that by pressing it, it creates a Segment which is an Entity in my CoreData with time data.
}
So far everything that I mentioned above is working. I am getting the location updates, showing the path on a MapView. I am able to create Segments (and save into CoreData) by pressing the Start button. Now the piece I am looking for is for every location update that goes into userLocations, I would like to create a new instance of another CoreData Entity that is called PointOnPath that is associated with a Segment. So Segment has a one-to-many relationship to PointOnPath. What I don't know is where I should call something like the following lines of code:
let point = PointOnPath(context: context)
point.latitude = location.coordinate.latitude
point.longitude = location.coordinate.longitude
point.segment = segment
try? context.save()
I thought about putting the above lines of code into:
var userPath: [CLLocationCoordinate2D]? {
if let userLocations = locationManager.userLocations {
// Maybe add to CoreData for PointOnPath here?
return userLocations.map( { $0.coordinate })
}
return nil
}
But I noticed this is being called many times. It seems to me it should only be called whenever a new userLocations?.append(location) happens but that's not the case and it's called many more times than userLocations?.append(location) happens. And in general I am not sure if that's the best place to save the location data in PointOnPath. Any insight is really appreciated.