iOS15下SwiftUI TextField绑定触发两次导致OTP重复提交如何修复?
问题原因
这是iOS15独有的系统级Bug,不属于代码逻辑错误。iOS15中UITextField调用resignFirstResponder()收起键盘时,会额外触发一次文本变更回调,导致自定义Binding的set块被执行两次,最终submitPin()被重复调用。更低版本的iOS系统无此异常逻辑。
修复方案
你可以任选以下任一方案解决问题,推荐优先使用方案1,兼容性最高:
方案1:增加请求状态防重校验
在submitPin内部添加状态判断,避免重复发起请求:
// 新增请求状态标记 private var isSubmitting = false private func submitPin() { // 仅当验证码长度符合要求且未在请求中时才执行逻辑 guard pin.count == maxDigits, !isSubmitting else { return } isSubmitting = true // 此处写入你的API请求逻辑 // 请求完成后如果需要支持用户重新输入,再重置isSubmitting为false即可 }
方案2:调整Binding触发逻辑
修改自定义Binding的set块,仅当输入长度首次达到阈值时才触发提交:
let boundPin = Binding<String>(get: { self.pin }, set: { newValue in // 截断超出最大长度的非法输入 self.pin = String(newValue.prefix(maxDigits)) // 只有输入长度刚好等于最大位数时才触发提交 if self.pin.count == maxDigits { self.submitPin() } })
同时可以移除TextField初始化参数中的onCommit: submitPin,避免用户手动触发提交时重复调用。
方案3:调整键盘收起的执行时机
将收起键盘的逻辑从introspect回调中移到请求前执行,避免和文本变更回调冲突:
// 新增持有textField实例的变量 @State private var textField: UITextField? private func submitPin() { guard pin.count == maxDigits, !isSubmitting else { return } isSubmitting = true // 先执行收起键盘逻辑 textField?.resignFirstResponder() // 再执行API请求 } // introspect部分修改为: .introspectTextField { textField in self.textField = textField textField.tintColor = .clear textField.textColor = .clear textField.keyboardType = .numberPad textField.textContentType = .oneTimeCode // 移除原有此处的resignFirstResponder/becomeFirstResponder逻辑 }
内容的提问来源于stack exchange,提问作者Venkata
相关产品推荐
相关产品推荐

