当 JSON 输入表示 Codable 类型的多个子类时使用 Codable
Using Codable when JSON input represents multiple subclasses of a Codable type
假设我有一些 JSON,像这样:
{
"some-random-key": {
"timestamp": 1234123423
"type": "text",
"content": "Hello!"
},
"some-other-key": {
"timestamp": 21341412314
"type": "image",
"path": "/path/to/image.png"
}
}
这个JSON代表两个消息对象。这是我想代表他们的方式(Swift 4):
class Message: Codable {
let timestamp: Int
// ...codable protocol methods...
}
class TextMessage: Message { // first message should map to this class
let content: String
// ...other methods, including overridden codable protocol methods...
}
class ImageMessage: Message { // second message should map to this class
let path: String
// ...other methods, including overridden codable protocol methods...
}
如何使用 JSON 中的 "type" 属性来告诉 Codable 要初始化哪个子类?我的第一直觉是使用枚举作为中介,它允许我在字符串表示和元类型之间穿梭
enum MessageType: String {
case image = "image"
case text = "text"
func getType() -> Message.Type {
switch self {
case .text: return TextMessage.self
case .image: return ImageMessage.self
}
}
init(type: Message.Type) {
switch type {
case TextMessage.self: self = .text
case ImageMessage.self: self = .image
default: break
}
}
}
但是这里的init导致编译错误-
Expression pattern of type 'TextMessage.Type' cannot match values of type 'Message.Type'
有没有 canonical/accepted 的方法来处理这种情况?为什么函数 getType 编译时此处的 init 不编译?
我会选择这种方法:
static func createMessage(with json: [String: Any]) -> Message? {
guard let typeString = json["type"] as? String,
let type = MessageType(rawValue: typeString) else { return nil }
switch type {
case .image: return ImageMessage(....
等等
"is" 关键字检查元类型是否表示另一个元类型的子类。此代码有效:
init(type: Message.Type) {
switch type {
case is TextMessage.Type: self = .text
case is ImageMessage.Type: self = .text
}
}
假设我有一些 JSON,像这样:
{
"some-random-key": {
"timestamp": 1234123423
"type": "text",
"content": "Hello!"
},
"some-other-key": {
"timestamp": 21341412314
"type": "image",
"path": "/path/to/image.png"
}
}
这个JSON代表两个消息对象。这是我想代表他们的方式(Swift 4):
class Message: Codable {
let timestamp: Int
// ...codable protocol methods...
}
class TextMessage: Message { // first message should map to this class
let content: String
// ...other methods, including overridden codable protocol methods...
}
class ImageMessage: Message { // second message should map to this class
let path: String
// ...other methods, including overridden codable protocol methods...
}
如何使用 JSON 中的 "type" 属性来告诉 Codable 要初始化哪个子类?我的第一直觉是使用枚举作为中介,它允许我在字符串表示和元类型之间穿梭
enum MessageType: String {
case image = "image"
case text = "text"
func getType() -> Message.Type {
switch self {
case .text: return TextMessage.self
case .image: return ImageMessage.self
}
}
init(type: Message.Type) {
switch type {
case TextMessage.self: self = .text
case ImageMessage.self: self = .image
default: break
}
}
}
但是这里的init导致编译错误-
Expression pattern of type 'TextMessage.Type' cannot match values of type 'Message.Type'
有没有 canonical/accepted 的方法来处理这种情况?为什么函数 getType 编译时此处的 init 不编译?
我会选择这种方法:
static func createMessage(with json: [String: Any]) -> Message? {
guard let typeString = json["type"] as? String,
let type = MessageType(rawValue: typeString) else { return nil }
switch type {
case .image: return ImageMessage(....
等等
"is" 关键字检查元类型是否表示另一个元类型的子类。此代码有效:
init(type: Message.Type) {
switch type {
case is TextMessage.Type: self = .text
case is ImageMessage.Type: self = .text
}
}