首页 > 解决方案 > 如何在 Swift 中的一个数组中声明不同的结构

问题描述

是否可以创建一个不同结构的数组?我的数据结构如下所示:

enum MovementType: String, Codable {
    case WeightMovement
    case RepsMovement
}

struct Movement: Identifiable, Codable {
    let id: UUID = UUID()
    let name: String
    let type: MovementType
    let workouts: [WeightMovement, RepsMovement] ---> A solution for this line based on the Type above
}

struct WeightMovement: Identifiable, Codable {
    let id: UUID = UUID()
    let weight: Double
    let sets: Int
    let reps: Int
}

struct RepsMovement: Identifiable, Codable {
    let id: UUID = UUID()
    let sets: Int
    let reps: Int
    let seconds: Int
}

应该做什么的一个简短示例:用户可以使用名称和运动类型创建多个运动。用户可以将锻炼添加到运动中,但由于每个运动类型包含不同的数据,因此我为此创建了不同的结构。

理想情况下,该数组将始终仅保存一种基于运动的type运动类型。

标签: swiftstruct

解决方案


理想情况下,该数组将始终根据运动类型仅保存一种运动类型。

在这种情况下,我建议手动解码 JSON并使用关联类型声明类型枚举

enum MovementType {
    case weight([WeightMovement])
    case reps([RepsMovement])
}

struct Movement: Identifiable, Decodable {
    
    private enum CodingKeys : String, CodingKey { case name, type, workouts }
    
    let id: UUID = UUID()
    let name: String
    let type: MovementType
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decode(String.self, forKey: .name)
        let movementType = try container.decode(String.self, forKey: .type)
        switch movementType {
            case "WeightMovement":
                let workouts = try container.decode([WeightMovement].self, forKey: .workouts)
                type = .weight(workouts)
            case "RepsMovement":
                let workouts = try container.decode([RepsMovement].self, forKey: .workouts)
                type = .reps(workouts)
            default: throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "Invalid movement type")
        }
    }
}

struct WeightMovement: Identifiable, Decodable {
    let id: UUID = UUID()
    let weight: Double
    let sets: Int
    let reps: Int
}

struct RepsMovement: Identifiable, Decodable {
    let id: UUID = UUID()
    let sets: Int
    let reps: Int
    let seconds: Int
}

明确的 UUID 分配意味着id不会被解码。


推荐阅读