从URL读取JSON的通用帮助函数发生错误 [英] Error at generic helper function for reading JSON from an URL

查看:81
本文介绍了从URL读取JSON的通用帮助函数发生错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的一个项目中,我想从多个视图中的多个URL中将JSON读取为多个结构,因此我决定编写一个小的但通用的辅助函数.

In one of my projects, I want to read JSON from several URLs in several Views into several structs so I decided to write a small, but generic helper function.

此函数应称为例如

查看1:

let call1 = Bundle.main.decode(iobrokerSection.self, from: "http://192.168.1.205:8087/get/javascript.0.Fahrzeiten.Dauer")

查看2:

let call2 = Bundle.main.decodeURL(iobrokerweather.self, from: "http://192.168.1.205:8087/get/javascript.0.Fahrzeiten.Weather")

以此类推.

对于第一个示例,结构iobrokerSection

For the first example the struct iobrokerSection is

struct iobrokerNumberDataPoint: Codable {
    var val: Int
    var ack: Bool
    var ts: Int
    var q: Int
    var from: String
    var user: String
    var lc: Int
    var _id: String
    var type: String
}

这是我的助手功能

extension Bundle {
    func decodeURL<T: Decodable>(_ type: T.Type, from urlString: String) -> T {
        guard let url = URL(string: urlString) else {
            fatalError("Placeholder for a good error message")
        }
        
        let request = URLRequest(url: url)
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            guard let loaded = try? JSONDecoder().decode(T.self, from: data!) else {
                fatalError("Placeholder for a good error message")
            }
        }.resume()

        return loaded
    }
}

我认为我理解为什么我得到编译器消息无法将Bool类型的返回表达式转换为T类型".处于返回加载"状态.

I think that I understand why I'm getting the compiler message "Cannot convert return expression of type Bool to return Type T" at "return loaded".

但是我不知道如何解决这个问题.

But I don't have any idea how to fix this.

有人可以给我一个提示吗?

May anyone give me a hint?

推荐答案

首先,Swift命名约定是用大写字母开头的所有结构,类和协议的名称.其次,您不能等待异步方法完成以返回值.您需要在方法中添加完成处理程序.第三,如果您的意图只是获取一些数据,则无需使用URLRequest.您可以只使用一个URL,然后将URL而不是字符串传递给您的方法.第四,不要强行解开可能为零的返回数据.您需要安全地解包可选数据,并在出现错误的情况下将其传递给完成处理程序.您的解码方法应如下所示:

First it is Swift naming convention to name all your structures, classes and protocols starting with an uppercase letter. Second you can't wait for an asynchronous method to finish to return a value. You need to add a completion handler to your method. Third you don't need to use a URLRequest if your intent is only to get some data. You can just use an URL and pass a URL to your method instead of a string. Fourth don't force unwrap the returned data it might be nil. You need to safely unwrap your optional data and in case of error pass it to the completion handler. Your decode method should look like something like this:

extension Bundle {
    func decode<T: Decodable>(_ type: T.Type, from url: URL, completion: @escaping (T?, Error?) -> Void) {
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else {
                completion(nil, error)
                return
            }
            do {
               try completion(JSONDecoder().decode(T.self, from: data), nil)
            } catch {
                completion(nil, error)
            }
        }.resume()
    }
}


调用此方法时,您需要在结果闭包内部获取异步结果:


When calling this method you need to get the asynchronous result inside the resulting closure:

struct IOBrokerNumberDataPoint: Codable {
    var val: Int
    var ack: Bool
    var ts: Int
    var q: Int
    var from: String
    var user: String
    var lc: Int
    var id: String
    var type: String
    enum CodingKeys: String, CodingKey {
        case val, ack, ts, q, from, user, lc, id = "_id", type
    }
}


let url = URL(string: "http://192.168.1.205:8087/get/javascript.0.Fahrzeiten.Dauer")!
Bundle.main.decode(IOBrokerNumberDataPoint.self, from: url) { brokerNumberDataPoint, error in
    guard let brokerNumberDataPoint = brokerNumberDataPoint else {
        print("error", error ?? "")
        return
    }
    print("brokerNumberDataPoint", brokerNumberDataPoint)
    // use brokerNumberDataPoint here
}


另一种选择是使用Swift 5 Result 通用枚举.

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

        }.resume()
    }
}


用法:


Usage:

let url = URL(string: "http://192.168.1.205:8087/get/javascript.0.Fahrzeiten.Dauer")!

Bundle.main.decode(from: url) { (result: Result<IOBrokerNumberDataPoint, Error>) in
    switch result {
    case let .success(brokerNumberDataPoint):
        print("brokerNumberDataPoint", brokerNumberDataPoint)
        // use brokerNumberDataPoint here
    case let .failure(error):
        print("error:", error)
    }
    
    
}

这篇关于从URL读取JSON的通用帮助函数发生错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆