I've seen similar questions on this but none that are up to date or work successfully, I've followed Apples Developer docs, various videos, and guides on how to do this but it still throws these warnings
2023-01-11 11:33:16.044044-0500 Walkman[50986:4824621] [SwiftUI] Publishing changes from within view updates is not allowed, this will cause undefined behavior.
It feels like I've tried everything from onChange() to @StateObject instead of @ObservedObject... It's those few lines because the warnings go away if the Map gets commented out.
The code that's causing the error is the
struct OrderView: View {
@ObservedObject var cartManager: CartManager
// @ObservedObject var locationManager: LocationManager
@EnvironmentObject var locationManager: LocationManager
@EnvironmentObject var viewModel: AppViewModel
@State private var tracking:MapUserTrackingMode = .follow
@State private var driversIn: Bool = false
var body: some View {
NavigationView {
// Text("Testing")
Map(
coordinateRegion: $locationManager.region,
interactionModes: MapInteractionModes.all,
showsUserLocation: true,
userTrackingMode: $tracking,
annotationItems: locationManager.MapLocations,
annotationContent: { item in
MapMarker(coordinate: item.coordinate, tint: .red)
// MapAnnotation(coordinate: item.location) {
// Rectangle()
// .stroke(Color.purple, lineWidth: 3)
// .frame(width: 10, height: 10)
// }
}
)
.navigationTitle("Orders")
.onAppear {
locationManager.getNearbyDrivers(query: GeoQuery(distance: 400, geo: locationManager.createGeo()))
}
.ignoresSafeArea()
// .onReceive(locationManager.$drivers, perform: { drivers in
//// print("DEBUG: DRIVERS _ \(drivers)")
// for driver in drivers {
// print("DEBUG: DRIVER TEST _ \(driver)")
// locationManager.MapLocations.append(MapLocation(id: driver.id, name: driver.name, latitude: driver.location.coordinates[0], longitude: driver.location.coordinates[1]))
// }
// })
}
}
}
Here is my LocationManager
final class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {
@Published var region = MKCoordinateRegion(center: MapDetails.startingLocation, span: MapDetails.defaultSpan)
@Published var authorizationStatus: CLAuthorizationStatus?
@Published var location: CLLocation?
@Published var MapLocations = [MapLocation]()
@Published var drivers = [Driver]()
var locationManager = CLLocationManager()
override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .authorizedWhenInUse:
authorizationStatus = .authorizedWhenInUse
manager.startUpdatingLocation()
break
case .restricted, .denied:
authorizationStatus = .restricted
manager.stopUpdatingLocation()
break
case .notDetermined:
authorizationStatus = .notDetermined
manager.requestWhenInUseAuthorization()
break
default:
break
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
DispatchQueue.main.async {
self.location = location
// self.MapLocations.append(MapLocation(name: "1", latitude: location.coordinate.latitude, longitude: location.coordinate.longitude))
// MARK - API for location calls, send when users location updates
print("DEBUG: Location: \(self.location?.coordinate.longitude ?? 0.00)")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("DEBUG: \(error.localizedDescription)")
}
func createGeo() -> GeoJSON {
return GeoJSON(coordinates: [locationManager.location?.coordinate.latitude ?? 0.00, locationManager.location?.coordinate.longitude ?? 0.00])
}
func getNearbyDrivers(query: GeoQuery) {
guard let url = URL(string: "http://localhost:8000/drivers-nearby") else { fatalError("Missing URL") }
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let payload: [String: Any] = [
"distance": query.distance,
"geo": ["type": "Point", "coordinates": query.geo.coordinates]
]
let data = try! JSONSerialization.data(withJSONObject: payload, options: [])
request.httpBody = data
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("Request error: ", error)
return
}
guard let response = response as? HTTPURLResponse else { return }
if response.statusCode == 200 {
guard let data = data else { return }
DispatchQueue.main.async {
do {
let drivers = try JSONDecoder().decode([Driver].self, from: data)
print("DEBUG: Drivers: \(drivers)")
self.drivers = drivers
for driver in self.drivers {
let location = MapLocation(id: driver.id, name: driver.name, latitude: driver.location.coordinates[0], longitude: driver.location.coordinates[1])
var driverIsVisible: Bool {
return self.MapLocations.contains(where: { annotation in
guard var driverAnno = annotation as? MapLocation else { return false }
print("DEBUG: cast driverAnno | driverAnno \(driverAnno.id) | driver \(driver.id)")
if driverAnno.id == driver.id {
print("DEBUG: Handle update driver position")
driverAnno.latitude = driver.location.coordinates[0]
driverAnno.longitude = driver.location.coordinates[1]
return true
}
return false
})
}
if !driverIsVisible {
print("DEBUG: Inserting map annotation \(location.id)")
self.MapLocations.append(location)
}
}
} catch let error {
print("Error decoding: ", error)
}
}
}
}
dataTask.resume()
}
//// private func geocode() {
//// guard let location = self.location else { return }
//// geocoder.reverseGeocodeLocation(location) { (places, error) in
//// if error == nil {
//// self.placemark = places?[0]
//// } else {
//// self.placemark = nil
//// }
//// }
//// }
}