Swift中如何通过回调闭包在ViewController与Checker之间传递数据并实现校验UI反馈
用闭包实现文本校验后的UI更新方案
嗨!作为Swift新手,能尝试用闭包替代通知真的很棒——闭包其实就是一种能在任务完成后直接传递结果的回调工具,比通知更贴合这种一对一的场景,逻辑也更清晰。我来一步步帮你改造代码:
第一步:改造CheckTextField类,添加闭包回调
首先咱们给校验类加个回调能力,让它能把校验结果“告诉”ViewController。先定义一个枚举来明确三种状态(空、正确、错误),然后给check方法添加闭包参数:
// 先定义校验结果的枚举,让状态更清晰 enum CheckResult { case empty case correct case incorrect } class CheckTextField { private let correctWord = "correct word" // 修改check方法,接受一个闭包参数,用来传递校验结果 func check(word: String, completion: (CheckResult) -> Void) { guard !word.isEmpty else { // 文本为空,返回empty状态 completion(.empty) return } if word == correctWord { completion(.correct) } else { completion(.incorrect) } } }
这里的completion就是闭包参数,它的类型是(CheckResult) -> Void——意思是“接受一个CheckResult类型的参数,没有返回值”。当校验完成时,我们调用这个闭包把结果传出去。
第二步:修改ViewController,用闭包处理校验结果
接下来咱们更新ViewController里的按钮点击逻辑,调用checker的校验方法,并通过闭包回调更新label的UI:
final class FeedViewController: UIViewController { private let checkTextField: UITextField = { let textField = MyCustomTextField( font: UIFont.systemFont(ofSize: 16), textColor: .black, backgroundColor: .white, placeholder: "Enter the word" ) return textField }() private lazy var checkButton: UIButton = { let button = MyCustomButton( title: "Check the word", titleColor: .white, backgroundColor: .systemGray, backgroundImage: nil ) { [weak self] in // 按钮点击时,调用校验逻辑 guard let self = self else { return } let inputWord = self.checkTextField.text ?? "" // 调用checker的check方法,传入闭包处理结果 self.checker.check(word: inputWord) { result in // 回到主线程更新UI(因为闭包可能在后台执行,UI操作必须在主线程) DispatchQueue.main.async { switch result { case .empty: self.colorLabel.alpha = 0 case .correct: self.colorLabel.alpha = 1 self.colorLabel.textColor = .green case .incorrect: self.colorLabel.alpha = 1 self.colorLabel.textColor = .red } } } } button.layer.cornerRadius = 6 button.clipsToBounds = true return button }() private let colorLabel: UILabel = { let label = UILabel() label.alpha = 0 label.toAutoLayout() return label }() private let checker: CheckTextField init(checker: CheckTextField) { self.checker = checker super.init(nibName: nil, bundle: nil) } // 别忘了添加required init(如果用代码创建VC的话) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
几个关键细节说明:
[weak self]:在按钮的闭包里用弱引用self,避免循环引用(按钮持有self,self持有按钮,闭包如果强引用self会导致内存泄漏)DispatchQueue.main.async:确保UI更新操作在主线程执行——虽然当前校验是同步的,但如果以后校验改成异步(比如网络请求),这一步能保证UI操作安全- 闭包直接接收
CheckResult,通过switch分支处理三种状态,逻辑一目了然
这样改造后,整个流程就变成了:按钮点击 → 调用checker校验 → 校验完成后通过闭包返回结果 → 更新label的颜色和透明度,比通知更直接,代码耦合度也更低。
内容的提问来源于stack exchange,提问作者Maria Mezhova
相关产品推荐
相关产品推荐

