如何为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
相关产品推荐
相关产品推荐

