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
}
CodePudding user response:
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.
CodePudding user response:
Property 'self.placeLibrary' not initialized at super.init call
The problem is not with your super.init()
call, but because you are trying to access a property of a class before this class is fully initialized (like the message says).
Edit: This seems odd at first. But you cannot guarantee the order that the compiler will call and initialize your class. You can only have certain that a class is fully initialized after init()
finishes. That's why you cannot use properties inside the init, by definition, only initialize.
Edit2: Easiest way to fix is make optional. If you have certain that this property will never go back to nil again you can make it automatically upwrapped with !
.
Edit3: Something like this:
import Foundation
import CoreLocation
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private var number: Int!
override init() {
super.init()
}
convenience init(test: Int) {
self.init()
self.number = test
}
}
class MyClass {
var location: LocationManager
init(location: LocationManager) {
self.location = location
}
}
Note the optional property here Int!