当JSON输入表示Codable类型的多个子类时使用Codable

时间:2017-08-04 05:18:02

标签: ios json swift swift4 codable

我们说我有一些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中的属性告诉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'
处理这种情况是否有规范/可接受的方式?当函数getType执行时,为什么init不在这里编译?

2 个答案:

答案 0 :(得分:0)

我会选择这种方法:

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(....

等等

答案 1 :(得分:0)

“is”关键字检查元类型是否表示另一个元类型的子类。此代码有效:

init(type: Message.Type) {
    switch type {
    case is TextMessage.Type: self = .text
    case is ImageMessage.Type: self = .text
    }
}