SwiftUI首次加载时LocationManager日志有值但模态视图无内容问题
首次加载应用时,控制台打印LocationManager的日志Current country code: US,但模态视图显示空文本:Looks like you're in !;手动修改模拟器位置为加拿大后,日志打印Current country code: CA,模态视图能正常显示Looks like you're in Canada!。
参考文件与代码
Countries.json
[ { "display_name": "United States of America", "searchable_names": [ "united states of america", "us", "usa" ], "image": "united-states-of-america", "id": 204, "iso": "US" }, { "display_name": "Canada", "searchable_names": [ "Canada", "ca" ], "image": "canada", "id": 205, "iso": "CA" } ]
核心代码
struct ContentView: View { @State private var isPresented = false @Binding var countries: [Country]; @State var modalCountry: Country? @StateObject var locationManager = LocationManager() var body: some View { VStack { // 视图内容 } .onChange(of: locationManager.countryCode) { country in self.isPresented = true } .sheet(isPresented: $isPresented) { ModalView(countryModal: self.modalCountry) } } } struct ModalView: View { @State var countryModal: Country? @Environment(\.presentationMode) var presentationMode var body: some View { VStack { Text("Looks like you're in \(countryModal?.display_name ?? "") !") .bold() Button("Show Me") {} Button("Dismiss") { presentationMode.wrappedValue.dismiss() } } .padding() } } class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject { let locationManager = CLLocationManager() @Published var countryCode: Country? override init() { super.init() locationManager.delegate = self locationManager.distanceFilter = 500 locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.startUpdatingLocation() } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let currentLocation = locations.last else { return } let geocoder = CLGeocoder() geocoder.reverseGeocodeLocation(currentLocation) { (placemarks, error) in guard let placemark = placemarks?.first, let countryCode = placemark.isoCountryCode else { return } print("Current country code: \(countryCode)") self.countryCode = countries.first(where: { $0.iso == countryCode }) ?? nil } } }
原因分析
1. modalCountry未与locationManager.countryCode同步
ContentView的onChange监听locationManager.countryCode变化时,仅执行了isPresented = true来弹出模态视图,但没有将最新的countryCode值赋值给modalCountry。首次加载时modalCountry初始值为nil,模态视图接收的参数为空,因此显示空白文本。
2. LocationManager无法访问countries数组,导致首次countryCode赋值失效
LocationManager的didUpdateLocations方法中,直接调用countries.first(where:...),但countries是ContentView的绑定属性,LocationManager并未持有该数组的引用——这会导致编译错误,实际运行中无法找到US对应的Country对象,使得self.countryCode仍为nil。
修复方案
同步modalCountry与locationManager.countryCode
修改ContentView的onChange回调,更新modalCountry的值:
.onChange(of: locationManager.countryCode) { newCountry in self.modalCountry = newCountry self.isPresented = true }
给LocationManager传入countries数组
修改LocationManager的初始化逻辑,接收countries参数:
class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject { let locationManager = CLLocationManager() @Published var countryCode: Country? private let countries: [Country] init(countries: [Country]) { self.countries = countries super.init() // 原有初始化逻辑不变 } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // 原有逻辑不变 self.countryCode = countries.first(where: { $0.iso == countryCode }) ?? nil } }
在ContentView中初始化时传入数组:
@StateObject var locationManager: LocationManager init(countries: Binding<[Country]>) { self._countries = countries self._locationManager = StateObject(wrappedValue: LocationManager(countries: countries.wrappedValue)) }
修正ModalView的参数定义
ModalView的countryModal无需用@State,改为普通常量即可:
struct ModalView: View { let countryModal: Country? @Environment(\.presentationMode) var presentationMode // 原有视图逻辑不变 }
内容的提问来源于stack exchange,提问作者mrJuei3l

