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

Swift解析iTunes API遇Decodable/Encodable协议不兼容问题

问题分析

你碰到的Type '_' does not conform to protocol Decodable / Encodable错误,核心原因很明确:Swift标准库的Result类型要实现Codable,必须保证它的Success和Failure关联类型都遵循Codable协议。常见触发场景有两种:

  1. 给Result指定的Success/Failure类型(比如自定义模型或错误)没实现Codable
  2. 自己定义了和标准库同名的Result类型,且这个自定义类型没实现Codable
修复方案

1. 确保关联类型遵循Codable

假设你要解析iTunes搜索API的返回数据,先定义符合Codable的基础模型:

// iTunes单条搜索结果模型
struct ITunesItem: Codable {
    let trackName: String?
    let artistName: String?
    let artworkUrl100: String?
    // 按需添加其他字段
}

// 自定义错误类型,必须遵循Codable(标准库Error不支持Codable)
enum APIError: Error, Codable {
    case invalidResponse
    case decodingFailed
}

// 带Result的API响应结构体
struct APIResponse: Codable {
    let result: Result<[ITunesItem], APIError>
}

这里关键是给Result的Failure关联类型用自定义的Codable错误枚举,而非标准库的Error。

2. 检查是否存在同名自定义Result类型

如果你自己写了一个Result结构体/枚举,且没实现Codable,就会触发这个错误。解决方式二选一:

  • 删掉自定义Result,直接用Swift标准库的版本
  • 给自定义Result补全Codable实现:
enum CustomResult<Success: Codable, Failure: Codable>: Codable {
    case success(Success)
    case failure(Failure)
    
    enum CodingKeys: String, CodingKey {
        case success, failure
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case .success(let value): try container.encode(value, forKey: .success)
        case .failure(let error): try container.encode(error, forKey: .failure)
        }
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let successVal = try container.decodeIfPresent(Success.self, forKey: .success) {
            self = .success(successVal)
        } else if let failureVal = try container.decodeIfPresent(Failure.self, forKey: .failure) {
            self = .failure(failureVal)
        } else {
            throw DecodingError.dataCorruptedError(
                forKey: .success, 
                in: container, 
                debugDescription: "No valid result field found"
            )
        }
    }
}

3. 更贴合iTunes API的优化方案

实际调用iTunes API时,官方返回的JSON里并没有success/failure这类Result对应的字段,直接把Result塞进响应结构体并不合理。更实用的方式是:

  • 定义仅对应API返回格式的响应模型:
struct ITunesSearchResponse: Codable {
    let resultCount: Int
    let results: [ITunesItem]
}
  • 在网络请求回调中用Result处理成功/失败:
func fetchiTunesData(searchTerm: String, completion: @escaping (Result<ITunesSearchResponse, Error>) -> Void) {
    guard let encodedTerm = searchTerm.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
          let url = URL(string: "https://itunes.apple.com/search?term=\(encodedTerm)") else {
        completion(.failure(NSError(domain: "Invalid URL", code: -1, userInfo: nil)))
        return
    }
    
    URLSession.shared.dataTask(with: url) { data, _, error in
        if let error = error {
            completion(.failure(error))
            return
        }
        
        guard let data = data else {
            completion(.failure(NSError(domain: "No data received", code: -2, userInfo: nil)))
            return
        }
        
        do {
            let response = try JSONDecoder().decode(ITunesSearchResponse.self, from: data)
            completion(.success(response))
        } catch {
            completion(.failure(error))
        }
    }.resume()
}

这种方式既符合API的实际返回结构,又通过Result统一处理了请求的成功/失败场景。

总结

如果坚持要把Result放进响应结构体,只需保证其泛型参数都遵循Codable即可;但更合理的思路是把Result用于网络请求的回调逻辑,而非作为数据模型的一部分。

内容的提问来源于stack exchange,提问作者Mason Bose

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:57:48