首页 > 解决方案 > 关于在 Swift 中删除对 Delegate Class 和 ViewController 的直接引用的问题

问题描述

我正在制作一个注册屏幕。我将 4 个 TextFields 作为 @IBOutlet Collection 连接到 ViewController。我创建了一个单独的 TextFieldDelegate 类来管理 UITextFieldDelegate。这里的问题是 TextFieldDelegate 直接引用 ViewController 来访问 TextField 集合。

TextFieldDelegate.swift

class TextFieldDelegate: NSObject, UITextFieldDelegate {
    private weak var signUpViewController: SignUpViewController?
    
    init(_ signUpViewController: SignUpViewController) {
        self.signUpViewController = signUpViewController
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
        textField.layer.borderWidth = 1
        textField.layer.borderColor = UIColor.systemBlue.cgColor
    }
    
    func textFieldDidChangeSelection(_ textField: UITextField) {
        guard let index = self.signUpViewController?.signUpTextFields.firstIndex(of: textField) else { return }
        guard let validatable = self.signUpViewController?.mapping(by: index) else { return }
}

SignUpViewController.swift

class SignUpViewController: UIViewController {
    
    @IBOutlet var signUpTextFields: [UITextField]! {
        didSet {
            signUpTextFields.forEach { textField in
                textField.delegate = textFieldDelegate
                textField.returnKeyType = .next
            }
        }
    }

    private lazy var textFieldDelegate = TextFieldDelegate(self)
}

问题代码

private weak var signUpViewController: SignUpViewController?
    
init(_ signUpViewController: SignUpViewController) {
    self.signUpViewController = signUpViewController
}

此问题中的代码是 TextFieldDelegate 直接引用 ViewController 的地方。除了直接引用此代码之外,还有其他方法可以访问 ViewController 吗?如果没有,我应该在需要访问 SignUpViewController 的 ViewController 中编写代码吗?

标签: iosswift

解决方案


这不是一个特别的“Swift 问题”,而是软件设计的一般问题。不过,我完全明白你为什么认为这是一个问题。

您可以使用事件或多个 Observable 替换直接引用,例如使用 RxSwift。然后,您SignUpViewController只需订阅您TextFieldDelegate触发的事件。

import Foundation
import UIKit
import RxSwift

class TextFieldDelegate: NSObject, UITextFieldDelegate {
    
    private let _didChangeSelection = PublishSubject<UITextField>()
    
    func textFieldDidChangeSelection(_ textField: UITextField) {
        _didChangeSelection.onNext(textField)
    }
    
    var didChangeSelection: Observable<UITextField> {
        return _didChangeSelection
    }
    
}

class SignUpViewController: UIViewController {
    
    //[...]
    private let disposables = DisposeBag()
    
    private func initSubscriptions() {
        Observable.merge(
            signupTextFields.compactMap {
                $0.delegate as? TextFieldDelegate
            }.map {
                $0.didChangeSelection
            }
        ).subscribe(onNext: { [weak self] textField in
            guard let index = self?.signUpTextFields.firstIndex(of: textField) else { return }
            guard let validatable = self?.mapping(by: index) else { return }
            //Your subscription code
        }).disposed(by: disposables)
    }
    
}


推荐阅读