如何从 alamofire 响应中获取任何类型的数组字段?

问题描述

我的 json 响应中有这样的字段:

"title": [2402,"Dr.","Prof.","Prof. Dr.","HM"]

我想解析它。我有我的模型类:

struct AppDataModel:Decodable {
    ...
    let title = Dictionary<String,Any>()
    
    
    enum CodingKeys: String,CodingKey{
        case title
        ...
    }
    ...
}

如您所见,我尝试使用 Dictionary<String,Any>()。而且我还考虑过 Any -> [Any] 的数组,但我通常会收到这样的错误

Type 'AppDataModel' does not conform to protocol 'Decodable'

我认为我必须像处理普通json一样处理它。但是我在 Swift 中没有找到这样的数据类型,只有字典。那么,也许有人知道如何处理这样的响应字段?

解决方法

struct AppDataModel: Codable {
    let title: [Title]?
}

extension AppDataModel {
    init(data: Data) throws {
        self = try newJSONDecoder().decode(AppDataModel.self,from: data)
    }

    init(_ json: String,using encoding: String.Encoding = .utf8) throws {
        guard let data = json.data(using: encoding) else {
            throw NSError(domain: "JSONDecoding",code: 0,userInfo: nil)
        }
        try self.init(data: data)
    }

    init(fromURL url: URL) throws {
        try self.init(data: try Data(contentsOf: url))
    }

    func with(
        title: [Title]?? = nil
    ) -> AppDataModel {
        return AppDataModel(
            title: title ?? self.title
        )
    }

    func jsonData() throws -> Data {
        return try newJSONEncoder().encode(self)
    }

    func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
        return String(data: try self.jsonData(),encoding: encoding)
    }
}

enum Title: Codable {
    case integer(Int)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Title.self,DecodingError.Context(codingPath: decoder.codingPath,debugDescription: "Wrong type for Title"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .integer(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

func newJSONDecoder() -> JSONDecoder {
    let decoder = JSONDecoder()
    if #available(iOS 10.0,OSX 10.12,tvOS 10.0,watchOS 3.0,*) {
        decoder.dateDecodingStrategy = .iso8601
    }
    return decoder
}

func newJSONEncoder() -> JSONEncoder {
    let encoder = JSONEncoder()
    if #available(iOS 10.0,*) {
        encoder.dateEncodingStrategy = .iso8601
    }
    return encoder
}

//use

do {
    let appDataModel = try AppDataModel(json)
}
catch{
    //handle error
}