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

SwiftUI中typeMismatch错误求助:代码修正方案

解决JSON解码中totalBooks等字段的类型不匹配问题

问题重现

运行代码时触发类型不匹配错误:

typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "userslist", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "totalBooks", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))

已处理id字段的数字/字符串兼容,但totalBooks、totalBookViews等字段存在同样问题——API返回数字类型,模型却定义为String类型。

修正方案

核心逻辑是给需要兼容数字/字符串的字段添加通用解码工具,避免重复编写try-catch逻辑,同时修复潜在的崩溃风险。

1. 新增通用解码扩展

在代码中添加KeyedDecodingContainer的扩展,封装兼容数字转字符串的解码逻辑:

extension KeyedDecodingContainer {
    // 处理必填字段:数字/字符串转String
    func decodeStringOrInt(forKey key: Key) throws -> String {
        do {
            return try decode(String.self, forKey: key)
        } catch DecodingError.typeMismatch {
            let intValue = try decode(Int.self, forKey: key)
            return String(intValue)
        }
    }
    
    // 处理可选字段:数字/字符串转String?
    func decodeOptionalStringOrInt(forKey key: Key) throws -> String? {
        guard contains(key) else { return nil }
        if let strValue = try? decodeIfPresent(String.self, forKey: key) {
            return strValue
        } else if let intValue = try? decodeIfPresent(Int.self, forKey: key) {
            return String(intValue)
        }
        return nil
    }
}

2. 修改UserslistModel的解码实现

替换原有的init(from decoder:)方法,使用工具方法处理兼容字段:

// MARK: - UserslistModel
public struct UserslistModel: Decodable, Hashable {
    public var id: String
    public var full_name: String
    public var totalBookViews: String
    public var totalBooks: String?
    public var full_address: String?
    
    private enum CodingKeys: String, CodingKey {
        case id, full_name, totalBookViews, totalBooks, full_address
    }
   
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // 固定字符串字段直接解码
        full_name = try container.decode(String.self, forKey: .full_name)
        full_address = try container.decodeIfPresent(String.self, forKey: .full_address)
        
        // 用工具方法处理兼容字段
        id = try container.decodeStringOrInt(forKey: .id)
        totalBookViews = try container.decodeStringOrInt(forKey: .totalBookViews)
        totalBooks = try container.decodeOptionalStringOrInt(forKey: .totalBooks)
    }
}

3. 修复View中的强制解包风险

原代码中Text(item.totalBooks!)使用强制解包,若API返回totalBooks为nil会直接崩溃,替换为默认值:

struct PublisherDataView: View{
    @StateObject var list = PublisherModelVM()
    @State var logourl: String?
    
    var body: some View{
        ScrollView(.horizontal,showsIndicators: false){
            HStack{
                ForEach( list.datas, id: \.id){ item in
                    VStack(spacing: 12){
                        Text(item.full_name )
                        Text(item.full_address ?? "-")
                        Text(item.totalBookViews)
                        // 替换强制解包为默认值
                        Text(item.totalBooks ?? "-")
                    }
                    .frame(width:275, height: 220)
                    .background(Color.brown.opacity(0.5)).cornerRadius(12)
                }
            }
        }
    }
}

额外说明

  • 通用解码工具可复用在所有需要兼容数字/字符串的字段上,减少冗余代码
  • 改用decodeIfPresent处理可选字段,避免API返回null时解码失败
  • 移除View中的强制解包,提升代码稳定性

内容的提问来源于stack exchange,提问作者Anup Kumar Mishra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 13:15:41