用通用数组 属性 解码结构

Decode struct with generic array property

我有以下带有泛型的结构,用于 API 分页响应:

struct Paginable<Body> {
    let data: [Body]
    let meta: Meta
}

extension Paginable {
    struct Meta: Codable {
        let pagination: Pagination

        struct Pagination: Codable {
            let total: Int
            let count: Int
            let perPage: Int
            let currentPage: Int
            let totalPages: Int
        }
    }
}

我希望能够像这样解码它:

let response  = try? response.decode(to: Paginable<Segment>.self)

所以这是我的尝试 Decodable:

extension Paginable where Body == Data {
    func decode<BodyType: Decodable>(to type: BodyType.Type) throws -> Paginable<BodyType> {
        guard let decodedJSON = try? JSONDecoder().decode(BodyType.self, from: data) else {
            throw APIError.decodingFailure
        }

        return Paginable<BodyType>(data: decodedJSON, meta: self.meta)
    }
}

这给了我两个错误:

  1. Cannot convert value of type 'Paginable.Meta' to expected argument type 'Paginable<_>.Meta'

return语句一致

如果我将 meta 属性 更改为 Int 等原始类型,错误就会消失。但是Meta本身就是Codable,所以这里有什么问题?

  1. Cannot convert value of type '[Data]' to expected argument type 'Data'

guard语句一致

如何解决这个问题?

你需要Paginable符合Codable,比如

struct Paginable<Body>: Codable where Body: Codable {
    let data: [Body]
    let meta: Meta
}

extension Paginable 中的 decode(data:to:) 方法更改为,

extension Paginable {
    static func decode<BodyType: Decodable>(data: Data, to type: BodyType.Type) throws -> BodyType? {
        do {
            let response = try JSONDecoder().decode(BodyType.self, from: data)
            return response
        } catch {
            throw error
        }
    }
}

用法:

if let data = str.data(using: .utf8) {
    do {
        let response = try Paginable<Segment>.decode(data: data, to: Paginable<Segment>.self)
        print(response)
    } catch {
        print(error)
    }
}

编辑:

JSON格式:

{
  "data": [
      {
        "name": "Name-1"
      },
      {
        "name": "Name-2"
      }
    ],
    "meta": {
      "pagination": {
        "total": 100,
        "count": 10,
        "perPage": 5,
        "currentPage": 1,
        "totalPages": 10
      }
    }
}