用Codable解析json任何类型

很抱歉,如果这个问题得到了多次回答,但我正在查找自己的特定json问题,这就是为什么要发布此问题,这是我的json,它是通知的数组列表,在其他对象中,您可以看到它具有合同对象,现在此对象正在更改,它可以在json数组的第二个索引中进行运动或反馈,我如何为此制作Codable结构以解码这种jsonHere是我的结构,我无法在Codable中执行任何类型

struct Alert: Decodable { var id: Int? var isUnread: Bool? var userId: Int? var message: String? var notificationType: String? var extra: Any?

 "value": [
        {
            "id": 153,"is_unread": true,"user_id": 3,"message": "Contract offered from JohnWick. Click here to see the details.","notification_type": "Contract","extra": {
                "contract": {
                    "id": 477,"likes": 0,"shares": 0,"account_reach": 0.0,"followers": 0,"impressions": 0.0,"description": "Fsafasd","budget": 0.0,"start_date": null,"end_date": null,"status": "pending","is_accepted": false,"brand_id": 443,"influencer_id": 3,"proposal_id": 947,"created_at": "2019-11-09T17:40:57.646Z","updated_at": "2019-11-09T17:40:57.646Z","contract_fee": 435345.0,"base_fee": 5000.0,"transaction_fee": 43534.5,"total_fee": 483879.5,"infuencer_completed": false,"brand_completed": false,"comments": 0
                }
            }
        },{
            "id": 152,"message": "Message from JohnWick. Click here to check your inbox.","notification_type": "Message","extra": {
                "message": {
                    "id": 495,"body": "Uuhvh","read": false,"conversation_id": 42,"created_at": "2019-11-08T13:44:02.055Z","updated_at": "2019-11-08T13:44:02.055Z"
                }
            }
        },]

如您所见,它可以是消息,广告系列,合同或反馈,所以我该如何使用CodingKeys Codable对此进行解析或为此建立模型

caoxc328 回答:用Codable解析json任何类型

一个简单的解决方案是制作一个名为Extra的结构,该结构对于每种情况都有四个可选属性。

struct Extra: Codable {
    let contract: Contract?
    let message: Message?
    let feedback: Feedback?
    let campaign: Campaign?
}

只要消息,活动,合同和反馈中的每一个都有固定的响应,那么您就应该能够为它们构造符合Codable的结构。

,

这里的意思不是Any。如您所说,extra可以是“消息,广告系列,合同或反馈”。它不能是UIViewController或CBPeripheral。不是“任何东西”。这是四件事之一。

“ X件事之一”是一个枚举:

enum Extra {
    case contract(Contract)
    case campaign(Campaign)
    case message(Message)
    case feedback(Feedback)
}

要使其可解码,我们只需要寻找正确的键即可:

extension Extra: Decodable {
    enum CodingKeys: CodingKey {
        case contract,campaign,message,feedback
    }

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

        // Try to decode each thing it could be; throw if nothing matches.
        if let contract = try? container.decode(Contract.self,forKey: .contract) {
            self = .contract(contract)
        } else if let campaign = try? container.decode(Campaign.self,forKey: .campaign) {
            self = .campaign(campaign)
        } else if let message = try? container.decode(Message.self,forKey: .message) {
            self = .message(message)
        } else if let feedback = try? container.decode(Feedback.self,forKey: .feedback) {
            self = .feedback(feedback)
        } else {
            throw DecodingError.valueNotFound(Self.self,DecodingError.Context(codingPath: container.codingPath,debugDescription: "Could not find extra"))
        }
    }
}
,

在本文中,您可以找到一种支持带有编码的任何类型的方法,因此JSON返回String或Int无关紧要:

anycodableValue

,

它不是Any类型,您有四种不同但可预测的类型。

参考Rob的答案,如果您将if - else if解码为枚举并根据其值解码子类型,则可以摆脱notificationType链中的解码尝试

enum NotificationType : String,Decodable {
    case contract = "Contract",message = "Message",campaign = "Campaign",feedback = "Feedback"
}

enum Extra {
    case contract(Contract)
    case campaign(Campaign)
    case message(Message)
    case feedback(Feedback)
}

struct Alert: Decodable {
    let id: Int
    let isUnread: Bool
    let userId: Int
    let message: String
    let notificationType: NotificationType
    let extra: Extra
    
    private enum CodingKeys : String,CodingKey { case id,isUnread,userId,notificationType,extra}
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self,forKey: .id)
        isUnread = try container.decode(Bool.self,forKey: .isUnread)
        userId = try container.decode(Int.self,forKey: .userId)
        message = try container.decode(String.self,forKey: .message)
        notificationType = try container.decode(NotificationType.self,forKey: .notificationType)
        switch notificationType {
            case .contract:
                let contractData = try container.decode([String:Contract].self,forKey: .extra)
                extra = .contract(contractData[notificationType.rawValue.lowercased()]!)
            case .campaign:
                let campaignData = try container.decode([String:Campaign].self,forKey: .extra)
                extra = .campaign(campaignData[notificationType.rawValue.lowercased()]!)
            case .message:
                let messageData = try container.decode([String:Message].self,forKey: .extra)
                extra = .message(messageData[notificationType.rawValue.lowercased()]!)
            case .feedback:
                let feedbackData = try container.decode([String:Feedback].self,forKey: .extra)
                extra = .feedback(feedbackData[notificationType.rawValue.lowercased()]!)
        }
    }
}
本文链接:https://www.f2er.com/3131720.html

大家都在问