You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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均无效。

错误原因

  1. Swift初始化规则限制:子类的所有存储属性必须在调用super.init()之前完成初始化。原代码中placeLibrary是未初始化的非可选存储属性,且在super.init()前还尝试访问placeLibrary.testPlace,违反了初始化规则。
  2. @ObservedObject使用错误:@ObservedObject是用于View中观察ObservableObject的属性包装器,在LocationManager这类非View类中不需要使用,直接持有实例即可。
  3. 无效的赋值语句:原代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 04:35:28