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

Swift中字符串格式浮点数相乘仅首个结果正确的问题排查

问题根因
  • 核心逻辑错误:在配置单个列表Cell时,遍历了当前搜索条目下整个service_details数组,每次循环都直接给当前Cell的价格label赋值,前面所有计算结果都会被后续循环的结果覆盖,最终Cell只会显示最后一次遍历算出的价格。感知到的“只有第一个结果正确”,本质是第一个Cell最终显示的价格刚好和预期的第一个服务价格重合,其余Cell的显示值全是对应条目下最后一个服务的价格,和预期不符。
  • 稳定性风险:代码中大量使用强制解包!,只要接口返回空值、非数字格式的字符串,会直接触发运行时崩溃。
  • 精度风险:用Float做货币金额计算会出现二进制浮点数精度误差,计算结果可能出现8.1999999、12.3400001这类不符合金额展示要求的值。
  • 冗余操作:汇率转换因子是接口返回的固定值,不需要每次遍历服务条目都重复做字符串转数值的操作。
修正方案

根据业务场景分两种情况实现,全程使用Decimal做金额计算规避精度问题,同时移除所有强制解包保证稳定性:

场景1:每个Cell对应单条服务明细

如果你的列表每一行对应service_details里的一条服务数据,不要在单Cell配置逻辑里遍历整个服务数组,直接按索引取当前行对应的服务数据计算即可:

// 建议在接口请求完成、拿到返回数据时就提前解析一次转换因子,全局复用
var convFactor: Decimal = 0
if let convStr = searchResult?.result?.conversion_factor?.conv_factor,
   let convVal = Decimal(string: convStr) {
    convFactor = convVal
}

// 以下是cellForRowAt中的Cell配置逻辑
// 先按你的层级拿到当前search_result条目
guard let sectionData = searchResult?.result?.search_result?[indexPath.section],
      let serviceList = sectionData.service_details,
      indexPath.row < serviceList.count else {
    cell.priceLbl.text = ""
    return
}
// 直接取当前行对应的服务数据,不需要遍历
let currentService = serviceList[indexPath.row]
var displayPrice = ""
if let rateStr = currentService.standard_rate_in_usd,
   let rateVal = Decimal(string: rateStr) {
    let finalPrice = rateVal * convFactor
    // 用NumberFormatter格式化金额,固定保留2位小数,符合货币展示规范
    let priceFormatter = NumberFormatter()
    priceFormatter.numberStyle = .decimal
    priceFormatter.minimumFractionDigits = 2
    priceFormatter.maximumFractionDigits = 2
    displayPrice = priceFormatter.string(from: finalPrice as NSNumber) ?? ""
}
cell.priceLbl.text = "£ \(displayPrice) \(currData)"

场景2:单个Cell展示当前搜索条目下所有服务的总价

如果业务要求每个Cell展示对应搜索条目下所有服务的总价,遍历时只做金额累加,等所有服务遍历完成、算出总价后再给label赋值,不要每次循环都修改label内容:

// 同样提前解析好转换因子convFactor
guard let sectionData = searchResult?.result?.search_result?[indexPath.row],
      let serviceList = sectionData.service_details else {
    cell.priceLbl.text = ""
    return
}
var totalPrice: Decimal = 0
for service in serviceList {
    if let rateStr = service.standard_rate_in_usd,
       let rateVal = Decimal(string: rateStr) {
        totalPrice += rateVal * convFactor
    }
}
// 遍历完成算完总价再格式化赋值
let priceFormatter = NumberFormatter()
priceFormatter.numberStyle = .decimal
priceFormatter.minimumFractionDigits = 2
priceFormatter.maximumFractionDigits = 2
let displayPrice = priceFormatter.string(from: totalPrice as NSNumber) ?? ""
cell.priceLbl.text = "£ \(displayPrice) \(currData)"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:42:17