MapKit/iOS16 - 紫色警告 [不允许从视图更新中发布更改...]

问题描述 投票:0回答:0

有一个非常普通的地图视图,显示 iPhone 的当前位置。

当我升级到 Swift 5.8 时,开始收到一些紫色警告。阅读本文后,这些将是 Xcode 处理数据方式的错误或变化。我正在使用 Xcode 15/beta 5。

错误出现在线路上:

class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {
}

 if CLLocationManager.locationServicesEnabled() {

以下分别是错误消息:

  • 不允许从视图更新中发布更改,这将 导致未定义的行为。
  • 如果在主程序上调用此方法,可能会导致 UI 无响应 线。相反,请考虑等待
    -locationManagerDidChangeAuthorization:
    回调和检查 首先
    authorizationStatus

完整代码如下:

import SwiftUI
import MapKit

class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {
}

struct LocationView: View {
    
    @Binding var selectedTab: TabChoice
    @Binding var calculated: CalculatedChoice
    
    @StateObject private var viewModel = LocationViewModel()
    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: GlobalVariables.latitude, longitude: GlobalVariables.longitude), span: MKCoordinateSpan(latitudeDelta: GlobalVariables.zoomLevel, longitudeDelta: GlobalVariables.zoomLevel))
    
    var body: some View {
        NavigationView {
            let displayTextLeft: String  = "Latitude: " + String(format: "%.3f°", (viewModel.region.center.latitude))
            let displayTextRight: String  = "Longitude: " + String(format: "%.3f°", (viewModel.region.center.longitude))
            //    "Altitude: " + String(format: "%.0fm", (LocationManager.location?.altitude))
           
            VStack {
                ZStack(alignment: .top) {
                    VStack{
                        Text("Location")
                            .viewTitle()
                        // MARK: MAP API
                        VStack(alignment: .leading, spacing: 12) {
                            Map(coordinateRegion: $viewModel.region, showsUserLocation: true)
                            // .ignoresSafeArea()
                                .accentColor(Color(.systemPink))
                                .onAppear {
                                    viewModel.checkIfLocationServicesIsEnabled()
                                }
                        }
                        .frame(width: GlobalVariables.screenWidth - 32, height: 340 + 30)  // 30 = top + bottom padding from CalculateView
                        .clipShape(RoundedRectangle(cornerRadius: 15))
                        .overlay(
                            RoundedRectangle(cornerRadius: 15)
                                .stroke(.black, lineWidth: 2)
                        )
                        .padding(.leading, 16)
                        .padding(.trailing, 16)
                        .offset(y: -30)
                        // MARK: GREY BANNER
                        HStack {
                            Rectangle().fill(Color.gray)
                                .frame(width: GlobalVariables.screenWidthPadding, height: 24)
                                .overlay(
                                    Text(displayTextLeft + "   " + displayTextRight)
                                        .greyBannerText()
                                )
                        }
                        .greyBannerPaddingRadius()
                        .offset(y: -24)
                        // MARK: TEXT
                        .frame(width: GlobalVariables.screenWidth, height: 24, alignment: .center)
                        VStack {
                            Text("How much solar power you can generate depends on where in the world you live. Not just how near the equator you are but the average amount of sunlight, cloud cover etc. Once your current location is showing correctly press the blue button below.")
                                .explanationTextPadding()
                        }
                        .offset(y: -24)
                        Spacer()
                        VStack {
                            // MARK: BUTTON
                            Button(action:
                                    { saveCoorindates()
                                selectedTab = TabChoice.calculate
                            }
                                   , label: { Text("Press to Save Current Location")
                                    .blueButtonTextFrame()
                            })
                            .blueButtonTextAttributes()
                            Spacer()
                                .frame(height: 20)
                        }
                    }
                }
                .onAppear {
                }
            }                                                   // NavigationStack
            .toolbar(.hidden)
            .navigationBarBackButtonHidden(true)
            .navigationViewStyle(.stack)
        }                                                       // VStack
    }
    
    
}

func saveCoorindates()  {
    GlobalVariables.latitude  = (CLLocationManager().location?.coordinate.latitude)!
    GlobalVariables.longitude = (CLLocationManager().location?.coordinate.longitude)!
    // GlobalVariables.altitude = (CLLocationManager().location?.coordinate.altitude)!
}

//  MARK: CLLOCATION MANAGER
final class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
    
    var locationManager:  CLLocationManager?
    @Published var region = MKCoordinateRegion(center: MapDetails.startingLocation, span: MapDetails.defaultSpan)
    
    func checkIfLocationServicesIsEnabled () {
      //  DispatchQueue.global().async {
            if CLLocationManager.locationServicesEnabled() {
                self.locationManager = CLLocationManager()
                self.locationManager!.delegate = self
                self.locationManager?.desiredAccuracy = kCLLocationAccuracyBest
            } else {
                print("Location services are not enabled, please turn on.")
            }
      //  }
    }
    
    private func checkLocationAuthorization() {
        guard let locationManager = locationManager else { return }
        switch locationManager.authorizationStatus {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .restricted:
            print("Your location is restricted due to parental controls.")
        case .denied:
            print("You have denied this app location permission. Go into settings to change it.")
        case .authorizedAlways, .authorizedWhenInUse :
            region = MKCoordinateRegion(center: locationManager.location!.coordinate, span: MKCoordinateSpan(latitudeDelta: GlobalVariables.zoomLevel, longitudeDelta: GlobalVariables.zoomLevel))
        @unknown default:
            break
        }
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        checkLocationAuthorization()
    }
    
}

如果我在 CLLocationManager.locationServicesEnabled() 周围放置一个 DispatchQueue,第二个紫色错误就会消失,但它不会获取我的位置并诉诸默认的经/纬度。

func checkIfLocationServicesIsEnabled () {
    DispatchQueue.global().async {
        if CLLocationManager.locationServicesEnabled() {
            self.locationManager = CLLocationManager()
            self.locationManager!.delegate = self
            self.locationManager?.desiredAccuracy = kCLLocationAccuracyBest
        } else {
            print("Location services are not enabled, please turn on.")
        }
    }
}
swift mapkit core-location locationmanager
© www.soinside.com 2019 - 2024. All rights reserved.