Ios 如何手动解码选定的密钥,并使用swift Decodable自动解码?
这是我正在使用的代码Ios 如何手动解码选定的密钥,并使用swift Decodable自动解码?,ios,swift,codable,decodable,encodable,Ios,Swift,Codable,Decodable,Encodable,这是我正在使用的代码 struct CreatePostResponseModel : Codable{ var transcodeId:String? var id:String = "" enum TopLevelCodingKeys: String, CodingKey { case _transcode = "_transcode" case _transcoder = "_transcoder" } enum Co
struct CreatePostResponseModel : Codable{
var transcodeId:String?
var id:String = ""
enum TopLevelCodingKeys: String, CodingKey {
case _transcode = "_transcode"
case _transcoder = "_transcoder"
}
enum CodingKeys:String, CodingKey{
case id = "_id"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: TopLevelCodingKeys.self)
if let transcodeId = try container.decodeIfPresent(String.self, forKey: ._transcode) {
self.transcodeId = transcodeId
}else if let transcodeId = try container.decodeIfPresent(String.self, forKey: ._transcoder) {
self.transcodeId = transcodeId
}
}
}
这里,transcodeId
由\u transcode
或\u transcoder
决定。
但是我希望
id
和其余的键(这里不包括)被自动解码。如何操作?在Codable
类型中实现init(from:)
后,需要手动解析所有键
struct CreatePostResponseModel: Decodable {
var transcodeId: String?
var id: String
enum CodingKeys:String, CodingKey{
case id, transcode, transcoder
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? ""
if let transcodeId = try container.decodeIfPresent(String.self, forKey: .transcode) {
self.transcodeId = transcodeId
} else if let transcodeId = try container.decodeIfPresent(String.self, forKey: .transcoder) {
self.transcodeId = transcodeId
}
}
}
在上述代码中
Codable
。使用可解码的就足够了
CodingKey
使用多个enum
。您可以使用单个枚举编码键
enum CodingKeys
中明确指定该case
的rawValue
。因此,在TopLevelCodingKeys
中不需要“\u transcode”
和“\u transcoder”
rawValues
keyDecodingStrategy
作为.convertFromSnakeCase
来处理下划线符号(snake-case-notation),即
因此,您不需要显式地处理所有的snake-case密钥。它将由
JSONDecoder
自行处理。这是一个很好的解决方案,您可以在任何地方为一个变量添加多个键:
var transcodeId:String?
public init(from decoder: Decoder) throws {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
transcodeId = container.getValueFromAvailableKey(codingKeys: [CodingKeys._transcoder,CodingKeys._transcode])
} catch {
print("Error reading config file: \(error.localizedDescription)")
}
}
extension KeyedDecodingContainerProtocol{
func getValueFromAvailableKey(codingKeys:[CodingKey])-> String?{
for key in codingKeys{
for keyPath in self.allKeys{
if key.stringValue == keyPath.stringValue{
do{
return try self.decodeIfPresent(String.self, forKey: keyPath)
} catch {
return nil
}
}
}
}
return nil
}
}
希望有帮助。编译器生成的
init(from:)
要么全是,要么全是。你不能让它解码一些键,而“手动”解码其他键
使用编译器生成的init(from:)
的一种方法是,为您的struct
提供可能的编码属性,并使transcodeId
成为计算属性:
struct CreatePostResponseModel: Codable {
var transcodeId: String? {
get { _transcode ?? _transcoder }
set { _transcode = newValue; _transcoder = nil }
}
var _transcode: String? = nil
var _transcoder: String? = nil
var id: String = “”
// other properties
}
你还需要手动解码其他密钥。谢谢你的回复,第1点:我也需要可编码,反之亦然。2:如果我在CodingKeys中保留了更多的键,而没有相应的变量,则会出现编译错误。3:属性名来自两个值(_transcoder和_transcode)中的任何一个。不完全是这样,我必须解码所有键:(是的,你必须这么做。你最好修改API以给出一致的响应。绝对同意。
struct CreatePostResponseModel: Codable {
var transcodeId: String? {
get { _transcode ?? _transcoder }
set { _transcode = newValue; _transcoder = nil }
}
var _transcode: String? = nil
var _transcoder: String? = nil
var id: String = “”
// other properties
}