在Swift中将JSON结果Map到枚举

lf5gs5x2  于 2023-09-30  发布在  Swift
关注(0)|答案(2)|浏览(92)

我从JSON服务得到以下响应:

[
    {
        "id": 1,
        "name": "Student"
    },
    {
        "id": 2,
        "name": "Faculty"
    }
]

我想把它Map到一个枚举:

enum Role: Int, Codable, Identifiable {
    case student
    case faculty
    
    var id: Int {
        rawValue
    }
}

但是我在Map时遇到了麻烦,因为JSON中的数组包含字典。

yzxexxkh

yzxexxkh1#

您的对象有2个成员:id是一个Int,name是一个字符串,你想使用它的枚举:

struct Role: Codable, Identifiable {
    enum RoleName: String, Codable {
        case student = "Student"
        case faculty = "Faculty"
    }
    var name: RoleName
    var id: Int
}

解码示例:

let json = """
[
    {
        "id": 1,
        "name": "Student"
    },
    {
        "id": 2,
        "name": "Faculty"
    }
]
"""

var roles = [Roles]()
if let data = json.data(using: .utf8) {
   roles = try? JSONDecoder().decode([Role].self, from: data)
}

编辑:更正了枚举的名称+编码键的类型

htrmnn0y

htrmnn0y2#

你需要的是一个定制的编码器和解码器。代码中的另一个问题是,您没有指定枚举案例的整数值,该值应以1开头(如果您不指定,则将以零开头)。所以你的枚举应该看起来像这样:

enum Role: Int, Codable, Identifiable {
    case student = 1, faculty
    var id: RawValue { rawValue }
    private enum CodingKeys: String, CodingKey {
        case id, name
    }
}

然后你可以创建一个自定义解码器:

extension Role {
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let id = try container.decode(Int.self, forKey: .id)
        let name = try container.decode(String.self, forKey: .name)
        switch (id, name) {
        case (1, "Student"):
            self = .student
        case (2, "Faculty"):
            self = .faculty
        default:
            throw DecodingError.dataCorrupted(
                .init(
                    codingPath: decoder.codingPath,
                    debugDescription: "Invalid Role data"
                )
            )
        }
    }
}

如果你需要编码,以及自定义编码器:

extension Role {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        switch self {
        case .student:
            try container.encode("Student", forKey: .name)
        case .faculty:
            try container.encode("Faculty", forKey: .name)
        }
    }
}

Playground测试:

let jsonData = Data(#"[{"id":1,"name":"Student"},{"id":2,"name":"Faculty"}]"#.utf8)
let roles: [Role] = [
    .init(rawValue: 1)!,
    .init(rawValue: 2)!
]
let encodedRoles = try JSONEncoder().encode(roles)
print(encodedRoles == jsonData)  // "true\n"
do {
    let decodedRoles = try JSONDecoder().decode([Role].self, from: jsonData)
    print(roles == decodedRoles)    // "true\n"
} catch {
    print(error)
}

相关问题