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

如何在locationManagerDidChangeAuthorization调用时触发SearchManagerViewModel方法

解决位置权限变更时自动更新城市名的问题

你的核心问题是:当用户在视图内切换位置服务权限时,SearchManagerViewModel没有感知到权限变化,无法自动触发城市搜索更新。下面是具体的解决方案,分步骤优化你的代码:


步骤1:给LocationManager添加权限状态的可监听属性

我们需要让LocationManager对外暴露权限状态的变化,这样上层的ViewModel可以感知到并做出响应:

final class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    
    private let locationManager = CLLocationManager()
    
    @Published var lastSearchedCity = ""
    @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined // 新增:对外暴露权限状态
    var hasFoundOnePlacemark: Bool = false

    func checkIfLocationServicesIsEnabled(){
        DispatchQueue.global().async {
            if CLLocationManager.locationServicesEnabled(){
                self.locationManager.delegate = self
                self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
                self.checkLocationAuthorization()
            }else{
                // 提示用户:位置服务已关闭
            }
        }
    }
    
    private func checkLocationAuthorization(){
        let status = locationManager.authorizationStatus
        self.authorizationStatus = status // 更新权限状态
        
        switch status{
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            // 提示用户:权限被限制/拒绝
            self.lastSearchedCity = "" // 权限失效时清空城市名
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.startUpdatingLocation()
        default:
            break
        }
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        checkLocationAuthorization()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        hasFoundOnePlacemark = false
        
        guard let location = manager.location else {
            self.locationManager.stopUpdatingLocation()
            return
        }
        
        CLGeocoder().reverseGeocodeLocation(location) { [weak self] placemarks, error in
            guard let self = self else { return }
            self.locationManager.stopUpdatingLocation()
            
            if let error = error {
                // 处理逆地理编码错误
                return
            }
            
            guard let placemark = placemarks?.first else {
                // 提示用户:未找到位置信息
                return
            }
            
            self.lastSearchedCity = placemark.locality ?? ""
        }
    }
}

步骤2:让SearchManagerViewModel自动监听权限和城市变化

修改ViewModel,使其自动监听LocationManager的权限变化和城市名更新,无需手动调用searchAndSetCity():

class SearchManagerViewModel: ObservableObject{
    @Published var cityName = ""
    
    private let locationManager = LocationManager()

    init() {
        // 自动同步LocationManager的城市名到ViewModel的cityName
        _ = locationManager.$lastSearchedCity
            .receive(on: DispatchQueue.main)
            .assign(to: &$cityName)
        
        // 监听权限状态变化,权限恢复时自动触发位置搜索
        _ = locationManager.$authorizationStatus
            .receive(on: DispatchQueue.main)
            .sink { [weak self] status in
                guard let self = self else { return }
                switch status {
                case .authorizedWhenInUse, .authorizedAlways:
                    self.locationManager.checkIfLocationServicesIsEnabled()
                case .denied, .restricted:
                    self.cityName = "" // 权限失效时清空显示
                default:
                    break
                }
            }
        
        // 初始化时自动检查一次位置服务
        locationManager.checkIfLocationServicesIsEnabled()
    }
    
    // 保留手动触发方法(如果需要)
    func searchAndSetCity(){
        locationManager.checkIfLocationServicesIsEnabled()
    }
}

步骤3:简化ContentView

现在视图无需在onAppear中手动调用方法,ViewModel会自动处理所有更新逻辑:

struct ContentView: View {

    @StateObject private var searchManager = SearchManagerViewModel()

    var body: some View {
        VStack {
            Text(searchManager.cityName)
                .font(.callout)
        }
    }
}

为什么这个方案有效?

  1. 权限变化感知:当用户切换位置服务权限时,LocationManager的locationManagerDidChangeAuthorization会被触发,更新authorizationStatus属性。SearchManagerViewModel通过监听这个属性,在权限恢复为授权状态时自动重新触发位置搜索。
  2. 实时城市同步:SearchManagerViewModel监听LocationManager的lastSearchedCity变化,自动同步到cityName,确保视图实时更新。
  3. 内存安全:使用weak self避免循环引用,同时优化了逆地理编码的可选绑定逻辑,提升代码稳定性。

内容的提问来源于stack exchange,提问作者fs_tigre

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:50:16