结构体的自定义编码

问题描述 投票:0回答:1

我正在尝试映射以下

SignUpRequest
结构

struct SignUpRequest: Encodable {

    struct Customer: Encodable {
        let email: String?
        let firstname: String?
        let lastname: String?
        let privacy: Bool
        let privacy2: Bool
    }

    let customer: Customer
    let password: String?

}

在这样的 JSON 中:

{
    "customer": {
        "email": "[email protected]",
        "firstname": "Mario",
        "lastname": "Rossi",
        "custom_attributes":[
            {
                "attribute_code":"consensopubb",
                "value":"3"
            },
            {
                "attribute_code":"consensopubb2",
                "value":"5"
            }
        ]
    },
    "password": "Password1!"
}

我尝试为我的结构创建自定义编码。

struct SignUpRequest: Encodable {

    let customer: Customer
    let password: String?

    struct Customer: Encodable {

        let email: String?
        let firstname: String?
        let lastname: String?
        let privacy: Bool
        let privacy2: Bool

        enum CodingKeys: String, CodingKey {
            case email
            case firstname
            case lastname
            case attributes = "custom_attributes"
        }

        enum AttributeCodingKeys: String, CodingKey {
            case code = "attribute_code"
            case value
        }

        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)

            try container.encode(email, forKey: .email)
            try container.encode(firstname, forKey: .firstname)
            try container.encode(lastname, forKey: .lastname)

            // ...

        }

    }

}

我的问题是我不知道如何将

privacy1
privacy2
属性编码为 JSON
custom_attributes
数组。

-- 编辑 --

privacy1
privacy2
属性是
Bool
因为映射了两个用户可以选中或不选中的复选框。不幸的是 API 需要一个
custom_attributes
数组。如果
consensopubb
"3"
,则
privacy1
具有值
true
。如果
consensopubb2
"5"
,则
privacy2
具有值
true

swift encodable
1个回答
0
投票

一个可能的解决方案:

struct SignUpRequest: Encodable {
    let customer: Customer
    let password: String?
}

extension SignUpRequest {
    
    struct Customer: Encodable {
        let email: String?
        let firstname: String?
        let lastname: String?
        let privacy1: Bool
        let privacy2: Bool
        
        enum CustomerCodingKeys: String, CodingKey {
            case email
            case firstname
            case lastname
            case attributes = "custom_attributes"
        }
        
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CustomerCodingKeys.self)
            var codes: [AttributeCode] = []
            if privacy1 {
                codes.append(AttributeCode(value: "3", code: "consensopubb"))
            }
            if privacy2 {
                codes.append(AttributeCode(value: "5", code: "consensopubb2"))
            }
            try container.encode(codes, forKey: .attributes)
            try container.encode(email, forKey: .email)
            try container.encode(firstname, forKey: .firstname)
            try container.encode(lastname, forKey: .lastname)
        }
    }
}
extension SignUpRequest.Customer {
    struct AttributeCode: Encodable {
        
        let value: String
        let code: String
        
        enum AttributeCodingKeys: String, CodingKey {
            case code = "attribute_code"
            case value
        }
    }
}

测试:

let requests: [SignUpRequest] = [SignUpRequest(customer: .init(email: "email1", 
                                                               firstname: "f1",
                                                               lastname: "l1",
                                                               privacy1: true,
                                                               privacy2: true),
                                               password: "p1"),
                                 SignUpRequest(customer: .init(email: "email2", 
                                                               firstname: "f2",
                                                               lastname: "l2",
                                                               privacy1: false,
                                                               privacy2: true),
                                               password: "p2"),
                                 SignUpRequest(customer: .init(email: "email3", 
                                                               firstname: "f3",
                                                               lastname: "l3",
                                                               privacy1: true,
                                                               privacy2: false),
                                               password: "p3"),
                                 SignUpRequest(customer: .init(email: "email4", 
                                                               firstname: "f4",
                                                               lastname: "l4",
                                                               privacy1: false,
                                                               privacy2: false),
                                               password: "p4")]


requests.forEach { aRequest in
    do {
        let encoder = JSONEncoder()
        encoder.outputFormatting = [.prettyPrinted, .sortedKeys] //For debug purposes
        let data = try JSONEncoder().encode(aRequest)
        let jsonString = String(data: data, encoding: .utf8)!
        print(jsonString)
    } catch {
        print("Error: \(error)")
    }
}

现在,我创建了一个自定义

AttributeCode
结构以使事情变得更容易。当然,您可以自定义所有
encode
并避免使用该结构(这很容易,因为它是
[String: String]
,但我觉得有时如果
encode(to:)
对于用户来说太困难了(以便以后调试、修改) ,或者
encode(to:)
乍一看不够清晰,最好有明确的额外结构,如果需要的话可以将其设为私有,并且只能由
SignUpRequest.Customer
看到。

我在

Customer
上进行了自定义编码,但事实上,如果只有那个需要特殊编码并且您不想修改
SignUpRequest
的编码(如果是),则可以通过对
Customer
进行其他修改来完成不是通过更高的
SignUpRequest
完成的),但是有了这个你应该有完整的想法。

© www.soinside.com 2019 - 2024. All rights reserved.