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

如何为iOS简易计算器集成NumberFormatter实现千位分隔?

iOS计算器千位分隔显示与输入异常修复

问题背景

为iOS简易计算器添加千位分隔显示(如10,000,000而非10000000)时,出现输入异常:依次按下7→8→9,界面显示77777777而非预期的789。

错误原因

修改后的numberPress方法存在核心逻辑错误:每次按下数字键时,错误地将输入值替换为当前textField的格式化显示文本,导致拼接时重复叠加已有内容。例如:

  • 按下7后,显示7
  • 按下8时,输入值被替换为7,拼接后显示77
  • 按下9时,输入值被替换为77,拼接后显示777

此外,直接操作带千位分隔的显示文本进行输入拼接本身不合理——显示文本包含格式化符号(逗号),不能直接作为输入源。

修复方案

通过维护原始未格式化的输入字符串分离输入逻辑与显示逻辑,彻底解决问题:

1. 添加原始输入存储变量

在ViewController的属性中新增:

var rawInputText: String = "0" // 存储用户输入的原始未格式化数字字符串

2. 重写输入处理方法

替换原numberPress方法,并新增显示更新方法:

@IBAction func numberPress(_ sender: UIButton) {
    guard let inputValue = sender.currentTitle else { return }
    
    // 处理正负号切换
    if inputValue == "±" {
        rawInputText = rawInputText.hasPrefix("-") 
            ? String(rawInputText.dropFirst()) 
            : "-\(rawInputText)"
        updateDisplayText()
        return
    }
    
    // 处理小数点输入
    if inputValue == "." {
        if !rawInputText.contains(".") {
            rawInputText += "."
        }
        updateDisplayText()
        return
    }
    
    // 处理数字输入
    if refreshTextField {
        rawInputText = inputValue
        refreshTextField = false
    } else {
        // 避免开头多个0(保留小数点前的单个0)
        rawInputText = rawInputText == "0" ? inputValue : rawInputText + inputValue
    }
    
    // 更新格式化后的显示文本
    updateDisplayText()
}

// 将原始输入格式化后更新到主显示框
private func updateDisplayText() {
    if let number = Double(rawInputText) {
        textFieldMain.text = printFormatter.string(from: NSNumber(value: number)) ?? rawInputText
    } else {
        textFieldMain.text = rawInputText
    }
}

3. 修正运算逻辑

替换原operatorPress方法,直接使用原始输入字符串转换数字,避免解析格式化文本:

@IBAction func operatorPress(_ sender: UIButton) {
    guard let newOperator = sender.titleLabel?.text, !rawInputText.isEmpty else { return }
    
    refreshTextField = true
    
    if currentOperator == "" && newOperator != "=" {
        valueA = Double(rawInputText) ?? 0
        currentOperator = newOperator
    } else {
        valueB = Double(rawInputText) ?? 0
        
        var result: Double = 0
        switch currentOperator {
        case "+": result = valueA + valueB
        case "-": result = valueA - valueB
        case "×": result = valueA * valueB
        case "÷": result = valueA / valueB
        default: result = valueB
        }
        
        // 更新历史记录:操作数显示无分隔格式,结果显示带千位分隔格式
        if currentOperator != "" {
            let valueAString = auxTotalFormatter.string(from: NSNumber(value: valueA)) ?? "\(valueA)"
            let valueBString = auxTotalFormatter.string(from: NSNumber(value: valueB)) ?? "\(valueB)"
            let resultString = printFormatter.string(from: NSNumber(value: result)) ?? "\(result)"
            textViewHistory.text! += "\(valueAString) \(currentOperator) \(valueBString) = \(resultString)\n"
        }
        
        // 重置状态
        currentOperator = ""
        valueA = newOperator != "=" ? result : 0
        valueB = 0
        rawInputText = "\(result)"
        
        // 更新显示
        updateDisplayText()
    }
}

4. 重置逻辑修正

修改allCancel方法,同步重置原始输入变量:

@IBAction func allCancel(_ sender: UIButton) {
    valueA = 0
    valueB = 0
    currentOperator = ""
    refreshTextField = true
    rawInputText = "0"
    textFieldMain.text = "0"
}

保留原格式化器配置

原定义的三个格式化器可以继续使用:

private let auxFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    let locale = Locale.current
    formatter.groupingSeparator = ""
    formatter.decimalSeparator = locale.decimalSeparator
    formatter.numberStyle = .decimal
    formatter.maximumIntegerDigits = 100
    formatter.minimumFractionDigits = 0
    formatter.maximumFractionDigits = 100
    return formatter
}()

private let auxTotalFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    formatter.groupingSeparator = ""
    formatter.decimalSeparator = ""
    formatter.numberStyle = .decimal
    formatter.maximumIntegerDigits = 100
    formatter.minimumFractionDigits = 0
    formatter.maximumFractionDigits = 100
    return formatter
}()

private let printFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    let locale = Locale.current
    formatter.groupingSeparator = locale.groupingSeparator
    formatter.decimalSeparator = locale.decimalSeparator
    formatter.numberStyle = .decimal
    formatter.maximumIntegerDigits = 9
    formatter.minimumFractionDigits = 0
    formatter.maximumFractionDigits = 8
    return formatter
}()

效果验证

修复后:

  • 输入7→8→9,界面显示789(超过千位时自动添加分隔符)
  • 运算结果和历史记录均按要求显示带千位分隔的格式
  • 正负号、小数点输入逻辑正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:27:00