SwiftUI中LocationManager类override init初始化报错求助
问题解决:SwiftUI中LocationManager初始化时未初始化placeLibrary的错误
问题描述
实现基于CoreLocation的LocationManager类时,引入PlaceLibrary实例后,override init()报错:
Property 'self.placeLibrary' not initialized at super.init call
尝试在super.init()前后添加self.placeLibrary = placeLibrary均无效。
错误原因
- Swift初始化规则限制:子类的所有存储属性必须在调用
super.init()之前完成初始化。原代码中placeLibrary是未初始化的非可选存储属性,且在super.init()前还尝试访问placeLibrary.testPlace,违反了初始化规则。 - @ObservedObject使用错误:
@ObservedObject是用于View中观察ObservableObject的属性包装器,在LocationManager这类非View类中不需要使用,直接持有实例即可。 - 无效的赋值语句:原代码中
self.placeLibrary = placeLibrary的右侧placeLibrary未定义,属于无效赋值。
解决方案
方案1:通过初始化参数传入PlaceLibrary实例
修改LocationManager的初始化方法,接收PlaceLibrary作为参数,在super.init()前完成属性初始化,同时移除@ObservedObject包装器:
import Foundation import CoreLocation import Combine import SwiftUI class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() // 直接持有PlaceLibrary实例,移除@ObservedObject let placeLibrary: PlaceLibrary @Published var locationStatus: CLAuthorizationStatus? @Published var lastLocation: CLLocation? @Published var distanceFromNearest: Double = 0.0 @Published var nearestObject: String = "" // 修改初始化方法,接收PlaceLibrary参数 init(placeLibrary: PlaceLibrary) { // 先初始化自身存储属性,再调用super.init() self.placeLibrary = placeLibrary super.init() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.startUpdatingLocation() } 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, _) in placeLibrary.testPlace.enumerated() { let currentLocation = CLLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude) let comparedLocation = CLLocation(latitude: placeLibrary.testPlace[idx].lat, longitude: placeLibrary.testPlace[idx].long) placeLibrary.testPlace[idx].proximity = currentLocation.distance(from: comparedLocation) } placeLibrary.testPlace = placeLibrary.testPlace.sorted(by: { $0.proximity < $1.proximity }) print(placeLibrary.testPlace) } }
在View中使用时,需先创建PlaceLibrary实例,再传入LocationManager:
struct ContentView: View { @StateObject private var placeLibrary = PlaceLibrary() @StateObject private var locationManager: LocationManager init() { _locationManager = StateObject(wrappedValue: LocationManager(placeLibrary: placeLibrary)) } var body: some View { Text("Location Status: \(locationManager.statusString)") } }
方案2:将PlaceLibrary设为单例
如果PlaceLibrary在全局只需要一个实例,可以将其改为单例,这样LocationManager可以直接在初始化时获取单例:
修改PlaceLibrary:
class PlaceLibrary: ObservableObject{ // 单例实例 static let shared = PlaceLibrary() @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) ] // 私有初始化方法,避免外部创建实例 private init() {} }
修改LocationManager的初始化:
override init() { self.placeLibrary = PlaceLibrary.shared super.init() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.startUpdatingLocation() }
这样在View中可以直接初始化LocationManager:
struct ContentView: View { @StateObject private var locationManager = LocationManager() var body: some View { Text("Location Status: \(locationManager.statusString)") } }
内容的提问来源于stack exchange,提问作者flyer74
相关产品推荐
相关产品推荐

