首页 > 解决方案 > Swift Decodable 用于混合类型的列表或项目

问题描述

在我最近开发的几个应用程序中,我需要阅读混合类型项目的列表。“现实生活”情况的一个很好的例子是文章中的项目列表:有标题、副标题、正文、图像等。

我想出了这样的事情:

// Sample data:
//
// {
//    items: [
//         {
//             "type": "a",
//             "a": "This one is A"
//         },
//         {
//             "type": "b",
//             "b": "This one is B"
//         }
//     ]
// }

import Foundation

// MARK: - "Root" protocol for all decodable items

protocol Item: Decodable {}

// MARK: - Items

struct ItemA: Item { let a: String }
struct ItemB: Item { let b: String }

// MARK: - Extractor

/// Helper for extracting items
struct ItemExtractor: Decodable {
    
    enum TypeKey: String, Decodable {
        case a
        case b
    }
    
    let item: Item
    
    // MARK: - Decodable compliance
    
    enum CodingKeys: String, CodingKey {
        case type
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        let type = try values.decode(TypeKey.self, forKey: .type)
        
        let itemValues = try decoder.singleValueContainer()
        
        // In particular, looking to eliminate this `switch`
        switch type {
        case .a:
            item = try itemValues.decode(ItemA.self)
        case .b:
            item = try itemValues.decode(ItemB.self)
        }
    }
}

// MARK: - Container

/// Container of items
struct MyList: Decodable {
    let items: [Item]
    
    // MARK: - Decodable compliance
    
    enum CodingKeys: String, CodingKey {
        case items
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        
        let extractors = try values.decode([ItemExtractor].self, forKey: .items)
        items = extractors.map { $0.item }
    }
}

现在的问题是:有没有一种方法可以概括此代码以避免 ItemExtractor 中的switch语句,如果有很多不同类型的项目,或者可能有完全不同的方法,这将特别有用?

期待更好的解决方案,–Baglan

标签: swiftlistdecodablemixed-type

解决方案


推荐阅读