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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 11:24:05