Нет, где здесь вы когда-либо звоните locationManager.requestWhenInUseAuthorization()
. Когда я это сделал (конечно, убедившись, что в Info.plist
есть запись для NSLocationWhenInUseUsageDescription
), он корректно обновил местоположение.
Например,
func getCurrentLocation() {
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
if let coordinate = locationManager.location?.coordinate {
currentLocation = coordinate
}
}
Это просто быстрое и грязное исправление, демонстрирующее, что оно работает. Но это не совсем правильно, потому что в первый раз, когда вы вызываете getCurrentLocation
, если он должен запросить у пользователя разрешение, что он делает асинхронно, это означает, что у него еще не будет местоположения, когда вы доберетесь до lastLocation
линия в вашей реализации. Это одноразовая вещь, но все же это не приемлемо. Вам нужно ваше CLLocationManagerDelegate
обновление currentLocation
, если это необходимо. Но, надеюсь, у вас достаточно здесь, чтобы диагностировать, почему ваше местоположение не фиксируется корректно CLLocationManager
.
FWIW, вы можете подумать об использовании userTrackingMode
из .follow
, что устраняет необходимость всего этого ручного менеджера местоположения и currentLocation
вещей. Единственное предостережение, о котором я упомяну (потому что я потратил часы один день, пытаясь диагностировать это любопытное поведение), это то, что userTrackingMode
не работает, если вы инициализируете свой вид карты с помощью:
let mapView = MKMapView()
Но это работает, если вы дадите ему какой-нибудь кадр, например:
let mapView = MKMapView(frame: UIScreen.main.bounds)
Итак, для режима отслеживания пользователя:
struct MapView: UIViewRepresentable {
@Binding var userTrackingMode: MKUserTrackingMode
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView(frame: UIScreen.main.bounds)
mapView.delegate = context.coordinator
mapView.userTrackingMode = userTrackingMode
return mapView
}
func updateUIView(_ view: MKMapView, context: Context) {
view.userTrackingMode = userTrackingMode
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
// MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) {
DispatchQueue.main.async {
self.parent.$userTrackingMode.wrappedValue = mode
}
}
// note, implementation of `mapView(_:viewFor:)` is generally not needed if we register annotation view class
}
}
И тогда мы можем иметь «следовать» кнопка, которая появляется, когда отслеживание пользователя отключено (чтобы вы могли включить его снова):
struct ContentView: View {
@State var userTrackingMode: MKUserTrackingMode = .follow
private var locationManager = CLLocationManager()
var body: some View {
ZStack {
MapView(userTrackingMode: $userTrackingMode)
.edgesIgnoringSafeArea(.all)
VStack {
HStack {
Spacer()
if self.userTrackingMode == .none {
Button(action: {
self.userTrackingMode = .follow
}) {
Text("Follow")
}.padding()
}
}
Spacer()
}
}.onAppear { self.requestAuthorization() }
}
func requestAuthorization() {
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
}
}