如何使用 Swift 解码器解码同一数组中的不同对象?

How can I decode different objects in the same array using Swift Decoder?

我正在加载用户通知,有不同的通知类型(如评论、关注),我需要根据它们的“类型”对每个通知进行解码 属性 但我是采用这种方法的新手,并且花了一整天的时间试图弄清楚如何做到这一点...

现在我一直在我的 NotificationsEnum 中收到解码错误,我认为这是因为我不知道如何访问返回的每个对象中的 type 属性在我的数组中。

我尝试使用这个 SO 问答 但它与 类 一起使用,而我正在使用结构。

如何根据对象的类型对每个对象进行解码 属性?我觉得我需要弄清楚如何以某种方式实现 nestedUnkeyedContainernestedContainer 但我很难让它工作。

另外,解码工作后,如何将所有这些对象放在同一个数组中?它会是泛型吗,因为我会打开它们的类型以将通知路由到不同的通知视图...??

谢谢你

不同JSONactivity我要根据类型解码

[
 {
   _id: 61dc9bde82d0715,
   type: 'like',
   username: 'testuser1',
   likeId: 61dcb2d0712
 },
 { 
   _id: 61dc9bde82d0715,
   type: 'follow',
   username: 'testuser2',
   followId: 61dc9bd2d0712
 },
 {
  _id: 61dc9b2d0715,
   type: 'comment',
   username: 'testuser3',
   commentId: 61dc9bb2d0712
 }
]

PROFILE/PARENT 数据模型

struct ProfileData: Decodable {
    **otherProperties**
    var notifications: [NotificationsEnum] 
    // ^ Is this correct type? Was thinking I might need some kind of generic array??
}

// 如何在这里实现 nestedUnkeyedContainer 和 nestedContainer???

enum NotificationsEnum: Decodable {
    enum DecodingError: Error {
        case wrongJSON
    }
  
    case like(LikeActivity)
    case comment(CommentActivity)
    case follow(FollowActivity)
    
    enum CodingKeys: String, CodingKey {
        case like = "like"
        case comment = "comment"
        case follow = "follow"
    }
    
   init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        switch container.allKeys.first {
        case .like:
            let value = try container.decode(LikeActivity.self, forKey: .like)
            self = .like(value)
        case .comment:
            let value = try container.decode(CommentActivity.self, forKey: .comment)
            self = .comment(value)
         case .follow:
            let value = try container.decode(FollowActivity.self, forKey: .follow)
            self = .follow(value)
        case .none:
             throw DecodingError.wrongJSON
        }
    }
}

型号

struct LikeActivity: Codable {
    let id: String
    let type: String
    let username: String
    let likeId: String
}

struct CommentActivity: Codable {
    let id: String
    let type: String
    let username: String
    let commentId: String
}

struct FollowActivity: Codable {
    let id: String
    let type: String
    let username: String
    let followId: String
}

您要做的是首先解码 type 然后使用解码值的切换并使用相同的 decoder 对象初始化相应的类型。

您也可以因此缩短 CodingKeys 枚举,因为我们只使用一个密钥。

enum CodingKeys: String, CodingKey {
    case type
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    let type = try container.decode(String.self, forKey: .type)
    switch type {
    case "like":
        self = try .like(LikeActivity(from: decoder))
    case "comment":
        self = try .comment(CommentActivity(from: decoder))
     case "follow":
        self = try .follow(FollowActivity(from: decoder))
    default:
         throw DecodingError.wrongJSON
    }
}

您还可以为 type 值创建一个枚举

enum ActivityType: String {
    case like, comment, follow
}

那么init(from:)中的switch就变成了

switch ActivityType(rawValue: type) {
case .like:
    self = try .like(LikeActivity(from: decoder))
case .comment:
    self = try .comment(CommentActivity(from: decoder))
case .follow:
    self = try .follow(FollowActivity(from: decoder))
default:
     throw DecodingError.wrongJSON
}