使用CLLocationManager无法获取用户位置的技术求助
无法通过CLLocationManager获取用户位置的问题
错误信息
运行应用时控制台输出:
[WeatherDataService] Response did not contain requested dataset: .appLocationConfig. Returning default value: AppLocationConfig(reportAnIssue: ReportIssueLocationConfig(position: beforeFooter, minDaysSinceInteraction: 0), expireTime: 2023-01-23 07:30:06 +0000
相关代码
LocationManager类及扩展
class LocationManager: NSObject, ObservableObject { @Published var currentLocation: CLLocation? private let locationManager = CLLocationManager() override init() { super.init() locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.distanceFilter = kCLDistanceFilterNone locationManager.requestAlwaysAuthorization() locationManager.startUpdatingLocation() locationManager.delegate = self } } extension LocationManager: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let location = locations.last, currentLocation == nil else { return } DispatchQueue.main.async { self.currentLocation = location } } }
视图代码(VStack部分)
VStack{ if let weather { VStack{ HStack{ Text("Singapore") .padding() .font(.largeTitle) VStack { Text("Condition: \(weather.currentWeather.condition.rawValue)") .font(.title2) Text("Temperature: \(weather.currentWeather.temperature.formatted())") .font(.title2) Text("Feels like: \(weather.currentWeather.apparentTemperature.formatted())") .font(.title2) // Text("Min: \() Max: \()") // .font(.title) } } Text("Today, \(weather.currentWeather.date.formatted())") .font(.subheadline) } ScrollView(.vertical){ VStack{ HourlyForcastView(hourWeatherList: hourlyWeatherData, hourlyWeatherData: hourlyWeatherData) TenDayForcastView(dayWeatherList: weather.dailyForecast.forecast) HStack{ // Humidity VStack{ Image(systemName: "humidity") .font(.system(size: 65)) .foregroundColor(.yellow) let humidity = (weather.currentWeather.humidity * 100) Text("HUMIDITY") .font(.headline) .foregroundColor(.white) Text("\(humidity.formatted())%") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) // Pressure VStack{ HStack{ Image(systemName: "arrow.down") .resizable() .frame(width: 40, height: 60) .foregroundColor(.yellow) Image(systemName: "arrow.down") .resizable() .frame(width: 40, height: 60) .foregroundColor(.yellow) Image(systemName: "arrow.down") .resizable() .frame(width: 40, height: 60) .foregroundColor(.yellow) } let pressure = (weather.currentWeather.pressure) Text("PRESSURE") .font(.headline) .foregroundColor(.white) Text("\(pressure.formatted())") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) } HStack{ // Dew Point VStack{ HStack{ Image(systemName: "drop") .font(.system(size: 56.5)) .foregroundColor(.yellow) Image(systemName: "drop") .font(.system(size: 56.5)) .foregroundColor(.yellow) } let dewPoint = (weather.currentWeather.dewPoint) Text("DEW POINT") .font(.headline) .foregroundColor(.white) Text("\(dewPoint.formatted())") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) // UV Index VStack{ Image(systemName: "sun.max") .font(.system(size: 53)) .foregroundColor(.yellow) let uvIndex = (weather.currentWeather.uvIndex) Text("UV INDEX") .font(.headline) .foregroundColor(.white) Text("\(uvIndex.value) - \(uvIndex.category.rawValue)") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) } HStack{ // Wind Speed VStack{ Image(systemName: "wind") .font(.system(size: 53)) .foregroundColor(.yellow) let windSpeed = (weather.currentWeather.wind) Text("WIND SPEED") .font(.headline) .foregroundColor(.white) Text("\(windSpeed.speed.formatted())") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) // Wind Direction VStack{ Image(systemName: "wind") .font(.system(size: 53)) .foregroundColor(.yellow) let windSpeed = (weather.currentWeather.wind) Text("WIND DIRECTION") .font(.headline) .foregroundColor(.white) Text("\(windSpeed.compassDirection.rawValue)") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) } HStack{ // Visibility VStack{ Image(systemName: "mountain.2") .font(.system(size: 53)) .foregroundColor(.yellow) let visibility = (weather.currentWeather.visibility) Text("VISIBILITY") .font(.headline) .foregroundColor(.white) Text("\(visibility.formatted())") .foregroundColor(.white) } .frame(width: 155) .padding() .background(content: {Color.blue}) .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous)) } } } } }
Task代码
} // This is where the VStack ends. .padding() .task(id: locationManager.currentLocation) { do { // if let location = locationManager.currentLocation { let location = CLLocation(latitude: 1.30437, longitude: 103.82458) self.weather = try await weatherService.weather(for: location) // } } catch { print(error) } }
当前临时方案
目前通过硬编码新加坡的坐标(CLLocation(latitude: 1.30437, longitude: 103.82458))来获取天气数据,但无法正常获取用户的实际位置。
解决方案
1. 配置Info.plist权限描述
使用requestAlwaysAuthorization()需要在Info.plist中添加以下权限说明:
- 添加
NSLocationAlwaysAndWhenInUseUsageDescription(字符串类型),填写权限用途,比如“需要获取您的位置以提供精准天气服务” - 添加
NSLocationWhenInUseUsageDescription(字符串类型),填写相同或对应用途说明
如果仅需前台获取位置,可以改用requestWhenInUseAuthorization(),但仍需配置NSLocationWhenInUseUsageDescription。
2. 完善LocationManager代理方法
添加权限状态监听和错误处理的代理方法到LocationManager扩展:
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { switch status { case .notDetermined: manager.requestAlwaysAuthorization() case .authorizedAlways, .authorizedWhenInUse: manager.startUpdatingLocation() case .denied, .restricted: print("位置权限被拒绝,请前往设置开启") @unknown default: break } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("获取位置失败:\(error.localizedDescription)") }
3. 调整初始化逻辑
将启动位置更新的代码移到权限授权成功后执行,修改LocationManager的init方法:
override init() { super.init() locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.distanceFilter = kCLDistanceFilterNone locationManager.delegate = self locationManager.requestAlwaysAuthorization() }
4. 修复Task逻辑
取消注释位置判断代码,确保仅在获取到用户位置后请求天气数据:
.task(id: locationManager.currentLocation) { do { if let location = locationManager.currentLocation { self.weather = try await weatherService.weather(for: location) } } catch { print(error) } }
关于.appLocationConfig错误
该错误来自WeatherDataService,与CLLocationManager无关,是天气服务返回数据缺少指定配置项,服务内部已返回默认值,不会影响位置获取功能,可忽略。
内容的提问来源于stack exchange,提问作者Aadish123
相关产品推荐
相关产品推荐

