PGD*_*Dev 18 ios swift codable decodable encodable
我目前正在处理Codable项目中的类型并遇到问题.
struct Person: Codable
{
var id: Any
}
Run Code Online (Sandbox Code Playgroud)
id在上面的代码中可以是a String或an Int.这就是id类型的原因Any.
我知道Any不是Codable.
我需要知道的是我如何才能使它发挥作用.
Luc*_*tti 22
首先,您可以定义一个可以从a String 和Intvalue 解码的类型.这里是.
enum QuantumValue: Decodable {
case int(Int), string(String)
init(from decoder: Decoder) throws {
if let int = try? decoder.singleValueContainer().decode(Int.self) {
self = .int(int)
return
}
if let string = try? decoder.singleValueContainer().decode(String.self) {
self = .string(string)
return
}
throw QuantumError.missingValue
}
enum QuantumError:Error {
case missingValue
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以像这样定义结构
struct Person: Decodable {
let id: QuantumValue
}
Run Code Online (Sandbox Code Playgroud)
而已.我们来试试吧!
id是Stringlet data = """
{
"id": "123"
}
""".data(using: String.Encoding.utf8)!
if let person = try? JSONDecoder().decode(Person.self, from: data) {
print(person)
}
Run Code Online (Sandbox Code Playgroud)
id是Intlet data = """
{
"id": 123
}
""".data(using: String.Encoding.utf8)!
if let person = try? JSONDecoder().decode(Person.self, from: data) {
print(person)
}
Run Code Online (Sandbox Code Playgroud)
Scr*_*ble 19
Codable需要知道要转换的类型.
首先,我会尝试解决不知道类型的问题,看看你是否可以修复它并使其更简单.
否则,我现在想到解决问题的唯一方法就是使用如下的泛型.
struct Person<T> {
var id: T
var name: String
}
let person1 = Person<Int>(id: 1, name: "John")
let person2 = Person<String>(id: "two", name: "Steve")
Run Code Online (Sandbox Code Playgroud)
Giu*_*nza 11
我解决了这个问题,定义了一个名为AnyDecodable的新Decodable Struct,因此我使用AnyDecodable而不是Any.它也适用于嵌套类型.
在游乐场试试这个:
var json = """
{
"id": 12345,
"name": "Giuseppe",
"last_name": "Lanza",
"age": 31,
"happy": true,
"rate": 1.5,
"classes": ["maths", "phisics"],
"dogs": [
{
"name": "Gala",
"age": 1
}, {
"name": "Aria",
"age": 3
}
]
}
"""
public struct AnyDecodable: Decodable {
public var value: Any
private struct CodingKeys: CodingKey {
var stringValue: String
var intValue: Int?
init?(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
init?(stringValue: String) { self.stringValue = stringValue }
}
public init(from decoder: Decoder) throws {
if let container = try? decoder.container(keyedBy: CodingKeys.self) {
var result = [String: Any]()
try container.allKeys.forEach { (key) throws in
result[key.stringValue] = try container.decode(AnyDecodable.self, forKey: key).value
}
value = result
} else if var container = try? decoder.unkeyedContainer() {
var result = [Any]()
while !container.isAtEnd {
result.append(try container.decode(AnyDecodable.self).value)
}
value = result
} else if let container = try? decoder.singleValueContainer() {
if let intVal = try? container.decode(Int.self) {
value = intVal
} else if let doubleVal = try? container.decode(Double.self) {
value = doubleVal
} else if let boolVal = try? container.decode(Bool.self) {
value = boolVal
} else if let stringVal = try? container.decode(String.self) {
value = stringVal
} else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "the container contains nothing serialisable")
}
} else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not serialise"))
}
}
}
let stud = try! JSONDecoder().decode(AnyDecodable.self, from: jsonData).value as! [String: Any]
print(stud)
Run Code Online (Sandbox Code Playgroud)
如果您对编码部分感兴趣,可以将我的结构扩展为AnyCodable.
编辑:我实际上做到了.
这是AnyCodable
struct AnyCodable: Decodable {
var value: Any
struct CodingKeys: CodingKey {
var stringValue: String
var intValue: Int?
init?(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
init?(stringValue: String) { self.stringValue = stringValue }
}
init(value: Any) {
self.value = value
}
init(from decoder: Decoder) throws {
if let container = try? decoder.container(keyedBy: CodingKeys.self) {
var result = [String: Any]()
try container.allKeys.forEach { (key) throws in
result[key.stringValue] = try container.decode(AnyCodable.self, forKey: key).value
}
value = result
} else if var container = try? decoder.unkeyedContainer() {
var result = [Any]()
while !container.isAtEnd {
result.append(try container.decode(AnyCodable.self).value)
}
value = result
} else if let container = try? decoder.singleValueContainer() {
if let intVal = try? container.decode(Int.self) {
value = intVal
} else if let doubleVal = try? container.decode(Double.self) {
value = doubleVal
} else if let boolVal = try? container.decode(Bool.self) {
value = boolVal
} else if let stringVal = try? container.decode(String.self) {
value = stringVal
} else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "the container contains nothing serialisable")
}
} else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not serialise"))
}
}
}
extension AnyCodable: Encodable {
func encode(to encoder: Encoder) throws {
if let array = value as? [Any] {
var container = encoder.unkeyedContainer()
for value in array {
let decodable = AnyCodable(value: value)
try container.encode(decodable)
}
} else if let dictionary = value as? [String: Any] {
var container = encoder.container(keyedBy: CodingKeys.self)
for (key, value) in dictionary {
let codingKey = CodingKeys(stringValue: key)!
let decodable = AnyCodable(value: value)
try container.encode(decodable, forKey: codingKey)
}
} else {
var container = encoder.singleValueContainer()
if let intVal = value as? Int {
try container.encode(intVal)
} else if let doubleVal = value as? Double {
try container.encode(doubleVal)
} else if let boolVal = value as? Bool {
try container.encode(boolVal)
} else if let stringVal = value as? String {
try container.encode(stringVal)
} else {
throw EncodingError.invalidValue(value, EncodingError.Context.init(codingPath: [], debugDescription: "The value is not encodable"))
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你可以在游乐场用这种方式测试它以前的json:
let stud = try! JSONDecoder().decode(AnyCodable.self, from: jsonData)
print(stud.value as! [String: Any])
let backToJson = try! JSONEncoder().encode(stud)
let jsonString = String(bytes: backToJson, encoding: .utf8)!
print(jsonString)
Run Code Online (Sandbox Code Playgroud)
如果您的问题是 id 的类型不确定,因为它可能是字符串或整数值,我可以向您推荐这篇博文:http : //agostini.tech/2017/11/12/swift-4-codable -在现实生活中的第 2 部分/
基本上我定义了一个新的 Decodable 类型
public struct UncertainValue<T: Decodable, U: Decodable>: Decodable {
public var tValue: T?
public var uValue: U?
public var value: Any? {
return tValue ?? uValue
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
tValue = try? container.decode(T.self)
uValue = try? container.decode(U.self)
if tValue == nil && uValue == nil {
//Type mismatch
throw DecodingError.typeMismatch(type(of: self), DecodingError.Context(codingPath: [], debugDescription: "The value is not of type \(T.self) and not even \(U.self)"))
}
}
}
Run Code Online (Sandbox Code Playgroud)
从现在开始,您的 Person 对象将是
struct Person: Decodable {
var id: UncertainValue<Int, String>
}
Run Code Online (Sandbox Code Playgroud)
您将能够使用 id.value 访问您的 ID
AnyCodable您只需使用Matt Thompson 的酷库AnyCodable中的类型即可。
例如:
import AnyCodable
struct Person: Codable
{
var id: AnyCodable
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11119 次 |
| 最近记录: |