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

Swift中两模型属性部分重叠,移除默认值引发Decodable兼容错误的解决

问题

项目中有两个属性结构略有差异的Swift模型(Instructions和Recipe),当移除Instructions模型中summary属性的默认值(即删除="")时,出现编译错误:Type 'Instructions' does not conform to protocol 'Decodable'。同时当前使用默认值的方式存在问题:API返回的summary数据无法覆盖属性的默认值,需要了解错误原因及解决办法。

错误原因分析
  1. Codable自动合成规则限制:
    Instructions模型定义了CodingKeys枚举,但其中没有包含summary字段。当summary带有默认值时,Swift会自动生成符合Decodable的实现:解码时如果API返回中没有summary字段,就使用属性的默认值;但如果移除默认值,summary变成了无默认值的非可选属性,此时自动生成的解码逻辑无法找到对应的CodingKey来获取值,也没有默认值兜底,因此不符合Decodable协议要求,触发编译错误。

  2. 默认值无法被API覆盖的原因:
    因为summary不在CodingKeys中,Swift自动生成的解码逻辑会完全忽略API返回的summary字段,直接使用属性定义时的默认值,导致API数据无法覆盖默认值。

解决方案

要同时解决编译错误和API数据覆盖问题,需要调整CodingKeys和属性的解码逻辑,以下是两种可行方案:

方案1:扩展CodingKeys并保留合理默认值

如果希望API返回的字段能覆盖默认值,同时在API无返回时使用默认值,只需将所有需要解码的字段(包括summary和其他带默认值的属性)加入CodingKeys,并保留属性的默认值:

struct Instructions: Codable, Hashable, Equatable {
    // 所有属性保留默认值(需要时可移除,比如summary如果API必传则去掉默认值)
    let vegetarian: Bool = false
    let vegan: Bool = false
    // ... 其他属性保持不变 ...
    let summary: String = "" // 若API必传可改为let summary: String
    // ... 其他属性 ...
    
    enum CodingKeys: String, CodingKey {
        // 加入所有需要解码的字段
        case id, title, image, imageType, winePairing, analyzedInstructions, extendedIngredients
        case vegetarian, vegan, glutenFree, dairyFree, veryHealthy, cheap, veryPopular, sustainable, lowFodmap, weightWatcherSmartPoints, gaps, preparationMinutes, cookingMinutes, aggregateLikes, healthScore, creditsText, license, sourceName, pricePerServing, readyInMinutes, servings, sourceUrl, summary, cuisines, dishTypes, diets, occasions, instructions, originalId, spoonacularScore, spoonacularSourceUrl
    }
}
  • 效果:Swift会自动生成解码逻辑,API返回的字段会覆盖对应属性的默认值;若API无返回,则使用属性定义的默认值。
  • 注意:如果summary是API必传字段,可直接去掉默认值写成let summary: String,此时因为CodingKeys包含summary,解码时会从API获取值,不会触发编译错误。

方案2:手动实现init(from:)解码方法

如果需要更灵活的解码逻辑(比如自定义默认值规则),可以手动实现Decodable的init(from:)方法:

struct Instructions: Codable, Hashable, Equatable {
    // 移除summary的默认值,改为非可选或可选类型
    let summary: String
    // ... 其他属性保持不变 ...
    
    enum CodingKeys: String, CodingKey {
        case id, title, image, imageType, winePairing, analyzedInstructions, extendedIngredients
        case summary // 必须加入summary
        // 若需要其他字段被API覆盖,也要加入对应的key
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // 解码必填字段
        id = try container.decode(Int.self, forKey: .id)
        title = try container.decode(String.self, forKey: .title)
        image = try container.decode(String.self, forKey: .image)
        imageType = try container.decode(String.self, forKey: .imageType)
        analyzedInstructions = try container.decode([AnalyzedInstructions].self, forKey: .analyzedInstructions)
        extendedIngredients = try container.decode([ExtendedIngredient].self, forKey: .extendedIngredients)
        winePairing = try container.decodeIfPresent(WinePairing.self, forKey: .winePairing)
        
        // 处理summary:API有值则用,无值则用空字符串兜底
        summary = try container.decodeIfPresent(String.self, forKey: .summary) ?? ""
        
        // 处理其他带默认值的属性,若需要API覆盖则同理解码
        vegetarian = try container.decodeIfPresent(Bool.self, forKey: .vegetarian) ?? false
        vegan = try container.decodeIfPresent(Bool.self, forKey: .vegan) ?? false
        // ... 其他属性按此逻辑处理 ...
    }
}
  • 效果:完全自定义解码逻辑,既解决了summary的编译错误,又能让API数据覆盖默认值,还能灵活处理各种边界情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 07:03:10