You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift调用The Movie DB API返回混合类型数组如何适配Identifiable渲染

最优处理方案

你最初定义枚举区分类型的思路是完全正确的,不需要更换实现方向,只需要补全枚举的Decodable逻辑、加上Identifiable协议遵循即可解决问题,你之前注释掉的id计算属性本身是可用的。

完整实现步骤

  1. 补全枚举的解码逻辑:The Movie DB的多类型搜索接口返回的每个结果条目都带有media_type字段,取值为movie/tv/person分别对应电影、剧集、演员,你可以根据这个字段手动实现枚举的解码逻辑。
  2. 给枚举加上Identifiable协议遵循,复用你之前写的id计算属性,即可满足列表渲染的协议要求。

完整代码示例

// 假设你的Movie、Show、Person结构体已经提前实现了Decodable、Identifiable协议
struct MultiSearchResults: Decodable {
    let page: Int
    let results: [Result]
    let total_results: Int
    let total_pages: Int
    
    enum Result: Decodable, Identifiable {
        case movie(Movie)
        case show(Show)
        case person(Person)
        
        var id: Int {
            switch self {
            case .movie(let movie):
                return movie.id
            case .show(let show):
                return show.id
            case .person(let person):
                return person.id
            }
        }
        
        // 手动实现解码逻辑
        enum CodingKeys: String, CodingKey {
            case mediaType = "media_type"
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            let mediaType = try container.decode(String.self, forKey: .mediaType)
            let singleValueContainer = try decoder.singleValueContainer()
            
            switch mediaType {
            case "movie":
                self = .movie(try singleValueContainer.decode(Movie.self))
            case "tv":
                self = .show(try singleValueContainer.decode(Show.self))
            case "person":
                self = .person(try singleValueContainer.decode(Person.self))
            default:
                throw DecodingError.dataCorruptedError(
                    forKey: .mediaType, 
                    in: container, 
                    debugDescription: "未知媒体类型: \(mediaType)"
                )
            }
        }
    }
}

列表渲染用法

实现后你可以直接遍历混合类型的结果数组,同时支持根据不同类型渲染不同的视图样式,比拆分数组更加灵活:

List {
    ForEach(searchResults.results) { result in
        switch result {
        case .movie(let movie):
            // 渲染电影条目视图
            MovieItemView(movie: movie)
        case .show(let show):
            // 渲染剧集条目视图
            ShowItemView(show: show)
        case .person(let person):
            // 渲染演员条目视图
            PersonItemView(person: person)
        }
    }
}

你的备选方案适用场景

  • 拆分三个独立数组:适合需要分标签/分栏单独展示不同类型结果的场景,可以通过compactMap快速过滤得到对应类型的数组,不需要修改现有结构:
    // 过滤得到所有电影结果
    let movies = searchResults.results.compactMap { result -> Movie? in
        guard case .movie(let movie) = result else { return nil }
        return movie
    }
    // 剧集、演员数组的过滤逻辑同理
    
  • 不遵循Identifiable渲染:完全没必要,即使不用Identifiable你也需要给ForEach指定唯一标识字段,实现成本更高,代码可读性也更低。

内容的提问来源于stack exchange,提问作者Damian Kociszewski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 04:15:05