2

作为一个整体,我对 ReactiveSwift 和 MVVM 非常陌生。我正在尝试验证输入到文本字段中的电话号码并根据验证结果启用/禁用按钮。

在应用程序中,有一个文本字段和一个UIButton名为提交的按钮。对于电话号码验证,我使用了一个名为[PhoneNumberKit][1]. 它还提供了一个UITextField格式化用户输入的子类。

我将一个看起来像这样的解决方案混合在一起。

class ViewController: UIViewController {
    @IBOutlet weak var textField: PhoneNumberTextField!
    @IBOutlet weak var submitButton: UIButton!


    override func viewDidLoad() {
        super.viewDidLoad()
        textField.becomeFirstResponder()
        submitButton.isEnabled = false

        let textValuesSignal = textField.reactive.continuousTextValues
        SignalProducer(textValuesSignal).start { result in
            switch result {
            case .value(let value):
                print(value)
                self.submitButton.isEnabled = self.isPhoneNumberValid(value)
            case .failed(let error):
                print(error)
                self.submitButton.isEnabled = false
            case .interrupted:
                print("inturrupted")
                self.submitButton.isEnabled = false
            case .completed:
                print("completed")
            }
        }
    }

    func isPhoneNumberValid(_ phoneNumberString: String) -> Bool {
        do {
            let phoneNumber = try PhoneNumberKit().parse(phoneNumberString)
            let formattedPhoneNumber = PhoneNumberKit().format(phoneNumber, toType: .e164)
            print("Phone number is valid: \(formattedPhoneNumber)")
            return true
        } catch let error {
            print("Invalid phone number: \(error)")
            return false
        }
    }
}

这可以完成工作,但不是很优雅。此外,用户输入和 UI 更改之间存在显着滞后。

另一件事是我上面的解决方案不符合 MVVM。我又试了一次。

class ViewController: UIViewController {
    @IBOutlet weak var textField: PhoneNumberTextField!
    @IBOutlet weak var submitButton: UIButton!

    private let viewModel = ViewModel()


    override func viewDidLoad() {
        super.viewDidLoad()
        textField.becomeFirstResponder()

        submitButton.reactive.isEnabled <~ viewModel.isPhoneNumberValid

        viewModel.phoneNumber <~ textField.reactive.continuousTextValues
    }
}

class ViewModel {
    let phoneNumber = MutableProperty("")
    let isPhoneNumberValid = MutableProperty(false)

    init() {
        isPhoneNumberValid = phoneNumber.producer.map { self.validatePhoneNumber($0) } // Cannot assign value of type 'SignalProducer<Bool, NoError>' to type 'MutableProperty<Bool>'
    }

    private func validatePhoneNumber(_ phoneNumberString: String) -> Bool {
        do {
            let phoneNumber = try PhoneNumberKit().parse(phoneNumberString)
            let formattedPhoneNumber = PhoneNumberKit().format(phoneNumber, toType: .e164)
            print("Phone number is valid: \(formattedPhoneNumber)")
            return true
        } catch let error {
            print("Invalid phone number: \(error)")
            return false
        }
    }
}

当我将validatePhoneNumber函数的结果分配给isPhoneNumberValid属性时,初始化程序中出现以下错误。

无法将“SignalProducer”类型的值分配给“MutableProperty”类型

我不知道如何将电话号码验证部分与提交按钮的isEnabled属性和点击操作正确连接。

演示项目

4

1 回答 1

3

尝试设置属性init并映射属性本身而不是生产者:

let isPhoneNumberValid: Property<Bool>

init() {
    isPhoneNumberValid = phoneNumber.map { ViewModel.validatePhoneNumber($0) }
}

您必须创建validatePhoneNumber一个静态方法,因为self它还不可用。

这是一种更典型的反应方式,因为您在视图模型初始化期间完全根据另一个属性定义了一个属性。

于 2019-08-31T18:25:25.683 回答