SwiftUI-使用CLLocationManager和CLGeocoder在API调用中定位

问题描述

我为此苦苦挣扎很长时间,没有找到我错了(我知道我错了)。

我有一个带有电话位置的API调用(此电话正在工作),但是我想要一个具有文本字段输入的手动位置的API调用(使用地理编码检索纬度/经度)。地理编码部分可以正常进行并且已更新,但未在API调用中传递。

我还希望通过带有电话位置的专用按钮清除TextField时触发此API调用

请,我想念什么?感谢您的帮助。

更新:这适用于Xcode 12.2 beta 2,并且应适用于Xcode 12.0.1

这是代码

我的模型

useParams()

我的viewmodel

import Foundation

struct MyModel: Codable {
    let value: Double
}

位置管理器

import Foundation
import SwiftUI
import Combine

final class Myviewmodel: ObservableObject {
    
    @Published var state = State.ready
    @Published var value: MyModel = MyModel(value: 0.0)
    @Published var manualLocation: String {
        didSet {
            UserDefaults.standard.set(manualLocation,forKey: "manualLocation")
        }
    }
    
    @EnvironmentObject var coordinates: Coordinates
    
    init() {
        manualLocation = UserDefaults.standard.string(forKey: "manualLocation") ?? ""
    }
    
    enum State {
        case ready
        case loading(Cancellable)
        case loaded
        case error(Error)
    }
    
    private var url: URL {
        get {
            return URL(string: "https://myapi.com&lat=\(coordinates.latitude)&lon=\(coordinates.longitude)")!
        }
    }
    
    let urlSession = URLSession.shared
    
    var dataTask: AnyPublisher<MyModel,Error> {
        self.urlSession
            .dataTaskPublisher(for: self.url)
            .map { $0.data }
            .decode(type: MyModel.self,decoder: JSONDecoder())
            .receive(on: RunLoop.main)
            .erasetoAnyPublisher()
    }
    
    func load(){
        assert(Thread.isMainThread)
        self.state = .loading(self.dataTask.sink(
            receiveCompletion: { completion in
                switch completion {
                case .finished:
                    print("⚠️ API Call finished")
                    break
                case let .failure(error):
                    print("❌ API Call failure")
                    self.state = .error(error)
                }
            },receiveValue: { value in
                self.state = .loaded
                self.value = value
                print("? API Call loaded")
            }
        ))
    }
}

视图

import Foundation
import SwiftUI
import Combine
import CoreLocation
import MapKit

final class Coordinates: NSObject,ObservableObject {
    
    @EnvironmentObject var myviewmodel: Myviewmodel
    
    @Published var latitude: Double = 0.0
    @Published var longitude: Double = 0.0
    
    @Published var placemark: CLPlacemark? {
        willSet { objectwillChange.send() }
    }
    
    private let locationManager = CLLocationManager()
    private let geocoder = CLGeocoder()
    
    override init() {
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    }
    
    deinit {
        locationManager.stopUpdatingLocation()
    }
}

extension Coordinates: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager,didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        latitude = location.coordinate.latitude
        longitude = location.coordinate.longitude
        
        geocoder.reverseGeocodeLocation(location,completionHandler: { (places,error) in
            self.placemark = places?[0]
        })
        self.locationManager.stopUpdatingLocation()
    }
}

extension Coordinates {
    
    func getLocation(from address: String,completion: @escaping (_ location: CLLocationCoordinate2D?)-> Void) {
        let geocoder = CLGeocoder()
        geocoder.geocodeAddressstring(address) { (placemarks,error) in
            guard let placemarks = placemarks,let location = placemarks.first?.location?.coordinate else {
                completion(nil)
                return
            }
            completion(location)
        }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)