我正在try 映射以下SON

{
    "items": [
        {
            "id": 4,
            "name": "Caffè",
            "is_active": true,
            "position": 5,
            "include_in_menu": true,
            "custom_attributes": [
                {
                    "attribute_code": "meta_title",
                    "value": "Caffè: scopri la linea completa online"
                },
                {
                    "attribute_code": "meta_description",
                    "value": "Scopri il caffè Hausbrandt nello shop ufficiale"
                }
            ]
        },
        {
            "id": 11,
            "name": "Tè",
            "is_active": true,
            "position": 15,
            "include_in_menu": true,
            "custom_attributes": [
                {
                    "attribute_code": "meta_title",
                    "value": "Acquista le Migliori Selezioni di Tè Online"
                },
                {
                    "attribute_code": "meta_description",
                    "value": "Scopri i Tè più pregiati sullo Shop Online"
                },
                {
                    "attribute_code": "thumbnail",
                    "value": "/shop/media/catalog/category/te01.jpg"
                }
            ]
        },
        {
            "id": 17,
            "name": "Tazzine",
            "is_active": true,
            "position": 14,
            "include_in_menu": true,
            "custom_attributes": [
                {
                    "attribute_code": "meta_title",
                    "value": "Tazze e Tazzine Caffè: scopri le Collezioni"
                },
                {
                    "attribute_code": "meta_description",
                    "value": "Acquista online le Tazze e Tazzine da Caffè Hausbrandt"
                },
                {
                    "attribute_code": "thumbnail",
                    "value": "/shop/media/catalog/category/tazzine_2.jpg"
                }
            ]
        }
    ]
}

在这样的a struct 中:

struct ShopCategory: Decodable {

    let id: Int
    let name: String
    let position: Int
    let isActive: Bool
    let isIncluded: Bool
    let thumbnail: String?
    let metaTitle: String?
    let metaDescription: String?
}

我就是这样实现的

struct ShopCategory: Decodable {

    let id: Int
    let name: String
    let position: Int
    let isActive: Bool
    let isIncluded: Bool
    let thumbnail: String?
    let metaTitle: String?
    let metaDescription: String?

}

extension ShopCategory {

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case position
        case isActive = "is_active"
        case isIncluded = "include_in_menu"
        case attributes = "custom_attributes"
    }

    init(from decoder: any Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try values.decode(Int.self, forKey: .id)
        self.name = try values.decode(String.self, forKey: .name)
        self.position = try values.decode(Int.self, forKey: .position)
        self.isActive = try values.decode(Bool.self, forKey: .isActive)
        self.isIncluded = try values.decode(Bool.self, forKey: .isIncluded)
        let attributes = try values.decodeIfPresent([AttributeCode].self, forKey: .attributes)
        self.thumbnail = attributes?.first(where: { $0.code == "thumbnail" })?.value
        self.metaTitle = attributes?.first(where: { $0.code == "meta_title" })?.value
        self.metaDescription = attributes?.first(where: { $0.code == "meta_description" })?.value

    }

}

extension ShopCategory: Hashable { }

private extension ShopCategory {

    struct AttributeCode: Decodable {

        let value: String
        let code: String

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

    }

}

它有效,但它不太喜欢我.我想避免搜索AttributeCode的array.我想解码类似于字典的类型,然后通过键访问属性.

但我不知道怎么做.

推荐答案

如果您只是想避免使用first来搜索,则可以将数组转换为如下词典:

let attributeArray = try values.decodeIfPresent([AttributeCode].self, forKey: .attributes) ?? []
// assuming the keys are unique...
let attributes = Dictionary(uniqueKeysWithValues: attributeArray.map { ($0.code, $0.value) })
self.thumbnail = attributes["thumbnail"]
self.metaTitle = attributes["meta_title"]
self.metaDescription = attributes["meta_description"]

如果您想根本避免使用数组,您可以将SON数组解码为这样的类型:

struct AttributeDictionary: Decodable {
    let attributes: [String: String]
    
    subscript(key: String) -> String? {
        get { attributes[key] }
    }
    
    enum CodingKeys: String, CodingKey {
        case code = "attribute_code"
        case value
    }
    
    init(from decoder: any Decoder) throws {
        // JSON arrays are decoded using an unkeyed container
        var unkeyedContainer = try decoder.unkeyedContainer()
        var dict = [String: String]()
        while !unkeyedContainer.isAtEnd {
            // go through the array and put each attribute into dict
            let attributeContainer = try unkeyedContainer.nestedContainer(keyedBy: CodingKeys.self)
            let code = try attributeContainer.decode(String.self, forKey: .code)
            let value = try attributeContainer.decode(String.self, forKey: .value)
            dict[code] = value
        }
        attributes = dict
    }
}

用途:

let attributes = try values.decodeIfPresent(AttributeDictionary.self, forKey: .attributes)
self.thumbnail = attributes?["thumbnail"]
self.metaTitle = attributes?["meta_title"]
self.metaDescription = attributes?["meta_description"]

Swift相关问答推荐

WWDC Swift并发会话中的厨房服务示例令人困惑

Variadic泛型与Swift中的值和类型参数包

在visionOS RealityView中使用.GenerateText时,未显示Reality Composer Promaterial 纹理

SwiftUI-如何使用剩余时间制作倒计时计时器

Swift通过设置变量B自动设置变量A的值

在 SwiftUI 视图中观察 UIViewRepresentable 的 @State var 变化

无论玩家移动到视图内的哪个位置,如何使用 SpriteKit 让敌人向玩家emits 子弹?

SwiftUI .task 视图修改器:运行在哪个线程中?

是否可以使用 .task 修饰符更新基于两个值的视图

MainActor 隔离可变存储属性为何会出现可发送错误?

XCUITest 在 TearDown 期间随机失败-无法终止 com.bundle.id

无法分配给属性:absoluteString是一个只能获取的属性

如何让 UIKit 挤压你的视图,使其适合屏幕

如何使用 Swift/iOS 为人类书写的笔画制作动画?

在 UItextfield 的右视图上添加一个按钮,文本不应与按钮重叠

你如何在 UIBarItem 中使用 setTitleTextAttributes:forState?

快速在 LLDB 中使用 po

如何在 Swift 中遍历 struct 属性?

Swift 3:小数到 Int

在 xcode8 中找不到 ModuleName-Swift.h 文件