【问题标题】:How to struct's value such that all views can access its values in Swift/SwiftUI?如何构造值以使所有视图都可以在 Swift/SwiftUI 中访问其值?
【发布时间】:2021-05-25 00:22:41
【问题描述】:

目前我正在解码来自 API 的 JSON 响应并将其存储到结构“IPGeolocation”中。我希望能够将此数据存储在变量中或返回此结构的实例,以便我可以访问视图中的值。

结构:

struct IPGeolocation: Decodable {
    var location: Coordinates
    var date: String
    var sunrise: String
    var sunset: String
    var moonrise: String
    var moonset: String
}

struct Coordinates: Decodable{
    var latitude: Double
    var longitude: Double
}

带有函数 getResult 的 URL 扩展:

extension URL {
    func getResult<T: Decodable>(completion: @escaping (Result<T, Error>) -> Void) {
        URLSession.shared.dataTask(with: self) { data, response, error in
            guard let data = data, error == nil else {
                completion(.failure(error!))
                return
            }
            do {
                completion(.success(try data.decodedObject()))
            } catch {
                completion(.failure(error))
            }
        }.resume()
    }
}

检索和解码数据的函数:

func getMoonTimes(lat: Double, long: Double) -> Void{
    urlComponents.queryItems = queryItems
    
    let url = urlComponents.url!
    
    url.getResult { (result: Result<IPGeolocation, Error>) in
        switch result {
        case let .success(result):
            print("Printing returned results")
            print(result)
        case let .failure(error):
            print(error)
        }
    }
}

我的目标是获取解码后的信息并将其分配给我的结构,以便之后在视图中使用。一旦函数运行,结果变量已经是一个 IPGeolocation 结构。我的问题在于存储它的最佳方式,甚至在必要时将其退回。

让 getResult 返回 IPGeolocation 有意义吗?有更好/不同的方法吗?

谢谢!

编辑:感谢 Leo Dabus 以下 cmets 的帮助,我做出了更改。

func getMoonTimes(completion: @escaping (IPGeolocation?,Error?) -> Void) {
        print("STARTING FUNC")
        let locationViewModel = LocationViewModel()
        let apiKey = "AKEY"
        let latitudeString:String = String(locationViewModel.userLatitude)
        let longitudeString:String = String(locationViewModel.userLongitude)
        var urlComponents = URLComponents(string: "https://api.ipgeolocation.io/astronomy?")!
        let queryItems = [URLQueryItem(name: "apiKey", value: apiKey),
                          URLQueryItem(name: "lat", value: latitudeString),
                          URLQueryItem(name: "long", value: longitudeString)]
    urlComponents.queryItems = queryItems
    urlComponents.url?.getResult { (result: Result<IPGeolocation, Error>) in
        switch result {
        case let .success(geolocation):
            completion(geolocation, nil)
        case let .failure(error):
            completion(nil, error)
        }
    }
}

从我的角度调用这个方法:

struct MoonPhaseView: View {
    getMoonTimes(){geolocation, error in
        guard let geolocation = geolocation else {
            print("error:", error ?? "nil")
            return
        }
    }
...
...
...

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    IMO 最好返回结果并处理错误。请注意,您分配了不应分配的相同名称结果。将其更改为case let .success(geolocation)。您需要为您的方法添加一个完成处理程序,因为请求异步运行并返回一个选项坐标和一个可选错误:

    请注意,我不确定您是否只想使用您的方法获取位置(坐标)或整个结构。但重点是为您的方法添加一个完成处理程序并传递您想要的属性或整个结构。

    func getMoonTimes(for queryItems: [URLQueryItem], completion: @escaping (Coordinates?,Error?) -> Void) {
        urlComponents.queryItems = queryItems
        urlComponents.url?.getResult { (result: Result<IPGeolocation, Error>) in
            switch result {
            case let .success(geolocation):
                completion(geolocation.location, nil)
            case let .failure(error):
                completion(nil, error)
            }
        }
    }
    

    用法:

    getMoonTimes(for: queryItems) { location, error in
        guard let location = location else {
            print("error:", error ?? "nil")
            return
        }
        print("Location:", location)
        print("Latitude:", location.latitude)
        print("Longitude:", location.longitude)
    }
    

    【讨论】:

    • 非常有帮助,谢谢。我想返回整个 IPGeolocation 结构,而不仅仅是坐标。我目前在 getMoonTimes 方法中创建 queryItems 并且不传递它们。我使用上面的完成闭包将 goelocation 作为 IPGeolocation 结构返回。我的理解是现在我应该能够在没有 for: queryItems 的情况下调用上述函数并分配给一个变量以在我的视图中使用。在 getMoonTimes 的第一行中使用“位置”时,它超出了范围,因为它没有被声明对吗?我将编辑以上内容以反映我所做的更改
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    相关资源
    最近更新 更多