I'm a new beginner in swiftUI and I'm trying to deal with a Class that use CoreLocation to do some places locations comparison. But I've add my structured array of place in my Class and I've got an error with the override init()
.
My class :
import Foundation
import CoreLocation
import Combine
import SwiftUI
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
@ObservedObject var placeLibrary: PlaceLibrary
@Published var locationStatus: CLAuthorizationStatus?
@Published var lastLocation: CLLocation?
@Published var distanceFromNearest: Double = 0.0
@Published var nearestObject:String = ""
override init() {
placeLibrary.testPlace = placeLibrary.testPlace
super.init() // HERE I GET MY ERROR
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
self.placeLibrary = placeLibrary
}
var statusString: String {
guard let status = locationStatus else {
return "unknown"
}
switch status {
case .notDetermined: return "notDetermined"
case .authorizedWhenInUse: return "authorizedWhenInUse"
case .authorizedAlways: return "authorizedAlways"
case .restricted: return "restricted"
case .denied: return "denied"
default: return "unknown"
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
locationStatus = status
print(#function, statusString)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
lastLocation = location
for (idx, readOnlyPlace) in placeLibrary.testPlace.enumerated() {
// Calculate stuff
let currentLocation = CLLocation(latitude: (self.lastLocation?.coordinate.latitude) ?? 0.0, longitude: (self.lastLocation?.coordinate.longitude) ?? 0.0)
let comparedLocation = CLLocation(latitude: readOnlyPlace.lat, longitude: readOnlyPlace.long)
// Update struct
placeLibrary.testPlace[idx].proximity = currentLocation.distance(from: comparedLocation)
}
placeLibrary.testPlace = placeLibrary.testPlace.sorted(by: { $0.proximity < $1.proximity })
print(placeLibrary.testPlace)
}
}
The error result here is : Property 'self.placeLibrary' not initialized at super.init call
After looking on internet I understand that I need to define all my variable used by my Class into the Init. That's why I add this line without any success : self.placeLibrary = placeLibrary
even if there is before or after the super.init()
line...
So I think there something I don't understand ...
My Place library :
class PlaceLibrary: ObservableObject{
@Published var testPlace = [
Place(lat: 46.1810, long: 6.2304, Name: "Place 1", proximity: 0.0),
Place(lat: 46.1531, long: 6.2951, Name: "Place 2", proximity: 0.0),
Place(lat: 46.1207, long: 6.3302, Name: "Place 3", proximity: 0.0)
]
}
My Place structure :
struct Place: Identifiable{
let id = UUID().uuidString
var lat: Double
var long: Double
var Name: String
var proximity: Double
init (lat: Double, long: Double, Name: String, proximity: Double){
self.lat = lat
self.long = long
self.Name = Name
self.proximity = proximity
}
init(config: NewPlaceConfig){
self.lat = config.lat
self.long = config.long
self.Name = config.Name
self.proximity = config.proximity
}
}
And finally my NewPlaceConfig
struct NewPlaceConfig{
var lat: Double
var long: Double
var Name: String
var proximity: Double
}
The placeLibrary
property is, like the error messages says, not initialized.
ObservedObject
, in this instance, does nothing. The @ObservedObject
property wrapper should only be used in View
structs. It tells the View
to observe the object for any changes, so that Swift knows when to redraw or recalculate the view. Other than that, it does nothing in regards to initialization.
So, really, the property is declared as var placeLibrary: PlaceLibrary
. This declaration does not initialize the property, it only describes the type that it will hold.
You can either initialize it yourself before the super.init
call using self.placeLibrary = PlaceLibrary()
, or, more concisely, initialize it at the property declaration site itself:
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
var placeLibrary = PlaceLibrary()
// ...
// Alternatively, initialize the property in the init()
override init() {
self.placeLibrary = PlaceLibrary()
super.init()
// ...
// Remaining initialization code
}
}
I would also replace var
with let
, but that is your choice.