如何使用 SwiftUI 获取当前位置?

How to get Current Location with SwiftUI?

正在尝试使用 swiftUI 获取当前位置。在代码下方,无法使用 didUpdateLocations 委托进行初始化。

class GetLocation : BindableObject {
    var didChange = PassthroughSubject<GetLocation,Never>()

    var location : CLLocation {
        didSet {
            didChange.send(self)
        }
    }
    init() {}
}

下面的代码有效(尚未准备好生产)。实施 CLLocationManagerDelegate 工作正常,lastKnownLocation 会相应更新。

别忘了在 Info.plist

中设置 NSLocationWhenInUseUsageDescription
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    private let manager = CLLocationManager()
    var lastKnownLocation: CLLocation?

    func startUpdating() {
        manager.delegate = self
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print(locations)
        lastKnownLocation = locations.last
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            manager.startUpdatingLocation()
        }
    }
}

从 Xcode 11 beta 4 开始,您需要将 didChange 更改为 willChange

var willChange = PassthroughSubject<LocationManager, Never>()

var lastKnownLocation: CLLocation? {
    willSet {
        willChange.send(self)
    }
}

我在 https://github.com/himbeles/LocationProvider 上写了一个包含使用说明的单文件 swift 包。它为 CLLocationManager 及其委托提供了一个 ObservableObject 类型的包装器 class。 有一个可以直接在SwiftUI中使用的@Published 属性 location,还有一个叫做locationWillChangePassthroughSubject<CLLocation, Never>可以通过Combine订阅。两者都在 CLLocationManager.

的每个 didUpdateLocations 事件上更新

它还处理位置访问先前被拒绝的情况:默认行为是向用户提出在应用程序设置中启用访问的请求,并link去那里。

在 SwiftUI(> iOS 14,> macOS 11)中,使用 as

import SwiftUI
import LocationProvider

struct ContentView: View {
    @StateObject var locationProvider = LocationProvider()
    
    var body: some View {
        VStack{
            Text("latitude \(locationProvider.location?.coordinate.latitude ?? 0)")
            Text("longitude \(locationProvider.location?.coordinate.longitude ?? 0)")
        }
        .onAppear {
            do {try locationProvider.start()} 
            catch {
                print("No location access.")
                locationProvider.requestAuthorization()
            }
        }
    }
}