Swift 通用 Json 解析器

Swift Generic Json Parser

我有这个通用的 JSON 解析器可以解码数组

class JSONParserFromStruct {
    typealias result<T> = (Result<[T], Error>) -> Void

    func downloadList<T: Decodable>(of _: T.Type,
                                    from data: Data,
                                    completion: @escaping result<T>) {
        do {
            let decodedData: [T] = try! JSONDecoder().decode([T].self, from: data)
            completion(.success(decodedData))
        } catch {
            completion(.failure(DataError.decodingError))
        }
    }
}

捆绑包中的这个 Users.json 文件

{
    "name": "Taylor Swift"
}

这样称呼它:

func performRequest() {
    let url = Bundle.main.url(forResource: "Users", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    genericParser.downloadList(of: User.self, from: data) { result in
        switch result {
        case let .failure(error):
            if error is DataError {
                print("eroarea este: \(error.localizedDescription)")

                print(url)

            } else {
                print("err is \(error.localizedDescription)")
            }
            print(error.localizedDescription)

        case let .success(weather):
            print(weather)
        }
    }
}

很有魅力

但是,当尝试使用另一个名为 Weather.json 的 json 文件时,失败并出现错误

"debugDescription: "Expected to decode Array but found a dictionary instead"

这是 json 我得到的错误是

{
    "main": {
        "temp": 281.52,
        "feels_like": 278.99,
        "temp_min": 280.15,
        "temp_max": 283.71,
        "pressure": 1016,
        "humidity": 93
    }
}

数据模型

struct Weather: Codable {
    let main: Main
}

struct Main: Codable {
    let temp: Double
}

...使用相同的 JSONParserFromStruct class,但它失败了。

是这样叫的

 func performRequest() {
    let url = Bundle.main.url(forResource: "Weather", withExtension: "json")!
    let data = try! Data(contentsOf: url)
    genericParser.downloadList(of: Weather.self, from: data) { result in
        switch result {
        case let .failure(error):
            if error is DataError {
                print("eroarea este: \(error.localizedDescription)")

                print(url)

            } else {
                print("err is \(error.localizedDescription)")
            }
            print(error.localizedDescription)

        case let .success(weather):
            print(weather)
        }
    }
}

第一种情况有效,因为它是一个类似于

的数组
[
{
"name": "Taylor Swift"
}
]

第二种情况不是 {} ,因此您可以通过制作单个 T 而不是 [T][ 来轻松修复它=19=] 或将 json 包装成

[  {
    "main": {
      "temp": 281.52,
      "feels_like": 278.99,
      "temp_min": 280.15,
      "temp_max": 283.71,
      "pressure": 1016,
      "humidity": 93
    } 

   }
]

您的解析器不够通用,因为它只能解码数组。

泛型类型 T 可以是任何东西,单个对象也可以是数组,所以只需使用 T

class JSONParserFromStruct {
    typealias ResultBlock<T> = (Result <T, Error>) -> Void

    func downloadList<T: Decodable>(of type: T.Type,
                                      from data: Data,
                                      completion: @escaping ResultBlock<T>) {

        do {
            let decodedData: T = try JSONDecoder().decode(T.self, from: data)
            completion(.success(decodedData))
        }
        catch {
            completion(.failure(DataError.decodingError))
        }
    }
}

要解码 User 数组,请将数组指定为参数类型

genericParser.downloadList(of: [User].self, from: data)

现在

genericParser.downloadList(of: Weather.self, from: data)

应该有效