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

Swift使用Codable解析JSON时将字符串数值转换为Float类型

解决方案

直接自定义Codable解码逻辑,在解析阶段完成字符串到Float的自动转换,同时兼容空字符串场景,解析完成后数值字段可直接参与计算,无需业务层再做类型转换。

处理规则

  • 课程的grade/weight/credits、作业的score/totalPoints字段类型从String改为Float,如果需要区分「无有效值」和「数值0」,可以改为可选类型Float?,空串/非法格式时解析为nil
  • 保留原有字段映射关系,不需要调整接口匹配规则
  • 空字符串、包含前后空格的字符串、非法数值字符串统一做容错处理,默认返回0(可根据业务需求调整默认值)

改造后完整代码

// MARK: - Welcome
struct Welcome: Codable {
    let currentClasses: [CurrentClass]
}

// MARK: - CurrentClass
struct CurrentClass: Codable {
    let name: String
    let grade, weight, credits: Float
    let lastUpdated: String
    let assignments: [Assignment]

    enum CodingKeys: String, CodingKey {
        case name, grade, weight, credits
        case lastUpdated = "Last Updated"
        case assignments
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        lastUpdated = try container.decode(String.self, forKey: .lastUpdated)
        assignments = try container.decode([Assignment].self, forKey: .assignments)
        
        let stringToFloat: (String) -> Float = { stringValue in
            let trimmed = stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
            guard !trimmed.isEmpty else { return 0 }
            return Float(trimmed) ?? 0
        }
        
        let gradeStr = try container.decode(String.self, forKey: .grade)
        grade = stringToFloat(gradeStr)
        
        let weightStr = try container.decode(String.self, forKey: .weight)
        weight = stringToFloat(weightStr)
        
        let creditsStr = try container.decode(String.self, forKey: .credits)
        credits = stringToFloat(creditsStr)
    }
}

// MARK: - Assignment
struct Assignment: Codable {
    let assignment: String
    let category: Category
    let dateAssigned, dateDue: String
    let score, totalPoints: Float
    
    enum CodingKeys: String, CodingKey {
        case assignment, category, dateAssigned, dateDue, score, totalPoints
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        assignment = try container.decode(String.self, forKey: .assignment)
        category = try container.decode(Category.self, forKey: .category)
        dateAssigned = try container.decode(String.self, forKey: .dateAssigned)
        dateDue = try container.decode(String.self, forKey: .dateDue)
        
        let stringToFloat: (String) -> Float = { stringValue in
            let trimmed = stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
            guard !trimmed.isEmpty else { return 0 }
            return Float(trimmed) ?? 0
        }
        
        let scoreStr = try container.decode(String.self, forKey: .score)
        score = stringToFloat(scoreStr)
        
        let totalPointsStr = try container.decode(String.self, forKey: .totalPoints)
        totalPoints = stringToFloat(totalPointsStr)
    }
}

enum Category: String, Codable {
    case majorGrades = "Major Grades"
    case minorGrades = "Minor Grades"
    case nonGraded = "Non-graded"
}

多场景复用优化

如果项目中存在大量字符串转数值的解析需求,可以抽成属性包装器减少重复代码:

@propertyWrapper
struct StringToFloat: Codable {
    let wrappedValue: Float
    
    init(wrappedValue: Float) {
        self.wrappedValue = wrappedValue
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let stringValue = try container.decode(String.self)
        let trimmed = stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
        wrappedValue = trimmed.isEmpty ? 0 : (Float(trimmed) ?? 0)
    }
}

使用时直接给对应字段添加装饰器即可,无需重写整个模型的初始化方法:

struct CurrentClass: Codable {
    let name: String
    @StringToFloat let grade, weight, credits: Float
    let lastUpdated: String
    let assignments: [Assignment]

    enum CodingKeys: String, CodingKey {
        case name, grade, weight, credits
        case lastUpdated = "Last Updated"
        case assignments
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 05:24:53