Swift教程:如何将数组中的字符串数值转换为Float类型
解决API返回字符串类型数值转Float的问题
一、推荐方案:用模型类实现类型安全解析
直接用Any和NSDictionary处理JSON很容易出现类型崩溃,建议先定义一个对应课程数据的模型结构体,在解析阶段就完成字符串到Float的转换,同时处理空字符串的情况:
struct Course: Codable { let name: String let grade: Float? // 空字符串转成nil let weight: Float? let credits: Float? let lastUpdated: String? let assignments: [Any] // 映射JSON里的"Last Updated"字段 enum CodingKeys: String, CodingKey { case name, grade, weight, credits, assignments case lastUpdated = "Last Updated" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: .name) // 处理grade:空字符串返回nil,否则转Float let gradeStr = try container.decodeIfPresent(String.self, forKey: .grade) ?? "" grade = gradeStr.isEmpty ? nil : Float(gradeStr) // 处理weight let weightStr = try container.decodeIfPresent(String.self, forKey: .weight) ?? "" weight = weightStr.isEmpty ? nil : Float(weightStr) // 处理credits let creditsStr = try container.decodeIfPresent(String.self, forKey: .credits) ?? "" credits = creditsStr.isEmpty ? nil : Float(creditsStr) lastUpdated = try container.decodeIfPresent(String.self, forKey: .lastUpdated) assignments = try container.decodeIfPresent([Any].self, forKey: .assignments) ?? [] } }
接着修改getData函数,用JSONDecoder直接解析成模型数组,让completion返回类型安全的[Course]:
func getData(_ completion: @escaping ([Course]) -> ()) { let urlPath = "https://gradual-deploy.vercel.app/students/currentclasses?username=john&password=doe" guard let url = URL(string: urlPath) else { completion([]) return } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data else { completion([]) return } do { // API返回的是外层数组包裹字典,先解析外层结构 let outerArray = try JSONDecoder().decode([[String: [Course]]].self, from: data) let currentClasses = outerArray.first?["currentClasses"] ?? [] completion(currentClasses) } catch { print("解析失败:\(error)") completion([]) } } task.resume() }
之后在闭包里就能直接用转换好的Float值:
getData { courses in for course in courses { print("课程:\(course.name)") if let grade = course.grade { print("成绩:\(grade)") } else { print("暂无成绩") } print("权重:\(course.weight ?? 0)") print("学分:\(course.credits ?? 0)") } }
二、快捷方案:直接在闭包中转换
如果不想修改原函数结构,也可以在闭包里逐个处理字典中的字符串:
getData { studentData in for item in studentData { guard let courseDict = item as? [String: Any] else { continue } // 转换grade let gradeStr = courseDict["grade"] as? String ?? "" let grade = gradeStr.isEmpty ? nil : Float(gradeStr) // 转换weight let weightStr = courseDict["weight"] as? String ?? "" let weight = weightStr.isEmpty ? nil : Float(weightStr) // 转换credits let creditsStr = courseDict["credits"] as? String ?? "" let credits = creditsStr.isEmpty ? nil : Float(creditsStr) // 使用转换后的值 print("课程名:\(courseDict["name"] ?? "未知")") print("成绩:\(grade ?? 0)") // 空值可以用默认0,或者按需处理 } }
注意点
- 空字符串直接转Float会返回nil,必须先判断字符串是否为空
- 如果字符串是非法数字(比如"abc"),
Float()也会返回nil,根据业务需求可以设置默认值或者跳过该数据 - 优先用模型类方案,代码更易维护,还能避免强制类型转换导致的崩溃
内容的提问来源于stack exchange,提问作者Abhi
相关产品推荐
相关产品推荐

