Reactive Cocoa: Function Reactive Programming!
Khởi động Auto Binding ~> Code Step 1 Tạo IBOutlet như bình thường chúng ta vẫn làm. // MARK: - IBOutlet @IBOutlet weak fileprivate var emailTextField: UITextField! @IBOutlet weak fileprivate var passwordTextField: UITextField! @IBOutlet weak fileprivate var ...
Khởi động
Auto Binding ~> Code Step 1 Tạo IBOutlet như bình thường chúng ta vẫn làm.
// MARK: - IBOutlet @IBOutlet weak fileprivate var emailTextField: UITextField! @IBOutlet weak fileprivate var passwordTextField: UITextField! @IBOutlet weak fileprivate var passwordAgainTextField: UITextField! @IBOutlet weak fileprivate var useCreditCardSwitch: UISwitch! @IBOutlet weak fileprivate var creditCardTextField: UITextField! @IBOutlet weak fileprivate var cardStatusLabel: UILabel! @IBOutlet weak fileprivate var verifyCardButton: UIButton! @IBOutlet weak fileprivate var activityIndicator: UIActivityIndicatorView! @IBOutlet weak fileprivate var registerButton: UIButton!
Step 2 binding View ~> viewModel
viewModel.email <~ emailTextField.reactive.continuousTextValues.skipNil() viewModel.password <~ passwordTextField.reactive.continuousTextValues.skipNil() viewModel.passwordAgain <~ passwordAgainTextField.reactive.continuousTextValues.skipNil() viewModel.useCreditCard <~ useCreditCardSwitch.reactive.isOnValues viewModel.creditCardNumber <~ creditCardTextField.reactive.continuousTextValues.skipNil()
Step 3 Proterties in viewModel được binding từ view(or controller)
/// Properties var email = MutableProperty<String>("") var password = MutableProperty<String>("") var passwordAgain = MutableProperty<String>("") var useCreditCard = MutableProperty<Bool>(false) var creditCardNumber = MutableProperty<String>("") var cardStatus = MutableProperty<CardStatus>(.notVerified)
Step 4 trong viewModel có các SignalProducer phát ra tín hiệu, view có thể bắt các sự kiện ở đây để cấu hình view
/// SignalProducer: phat tin hieu var correctEmailProducer: SignalProducer<Bool, NoError>! var correctPasswordProducer: SignalProducer<Bool, NoError>! var correctCreditCardProducer: SignalProducer<Bool, NoError>! var correctInputProducer: SignalProducer<Bool, NoError>!
Step 5 Cấu hình SignalProducer, và các giá trị mặc định.
// cau hinh tin hieu va property extension RegisterViewModel { func initBindings() { //tao trang thai mac dinh creditCardNumber creditCardNumber.producer.startWithValues { _ in self.cardStatus.value = .notVerified } //kiem tra email correctEmailProducer = email.producer .map({ (emailText) -> Bool in emailText.isValidEmailContains() }) //kiem tra pass correctPasswordProducer = SignalProducer.combineLatest(password.producer, passwordAgain.producer) .map { (passwordText, passwordAgainText) -> Bool in return (passwordText.characters.count > 5) && (passwordText == passwordAgainText) } //kiem tra card correctCreditCardProducer = SignalProducer.combineLatest(useCreditCard.producer, cardStatus.producer) .map({ (useCard, cardStatus) -> Bool in if !useCard { return true } else if cardStatus == .verified { return true } return false }) //kiem tra email password va card correctInputProducer = SignalProducer.combineLatest(correctEmailProducer, correctPasswordProducer, correctCreditCardProducer) .map({ (email, password, card) -> Bool in return email && password && card }) } //khi button verify duoc press se goi ham nay func verifyCardNumber() { cardStatus.value = .verifying ServiceHelper.sharedInstance.validateCreditCardNumber(creditCardNumber.value) .startWithValues { valid in self.cardStatus.value = valid ? .verified : .denied } } //khi button register duoc press se goi ham nay func createMainAppViewModel() -> MainAppViewModel { let mainAppViewModel = MainAppViewModel() mainAppViewModel.email = email.value mainAppViewModel.creditCardNumber = useCreditCard.value ? creditCardNumber.value : nil return mainAppViewModel } }
Step 6 ở view đơn giản mình sẽ lắng nghe từ viewModel,cấu hình view khi có sự kiện(vd correct pass thì enable button)
// lang nghe su kien emailTextField change all value emailTextField.reactive.continuousTextValues.skipNil().observeValues { email in print(email) } // lang nghe tin hieu correctEmailProducer viewModel.correctEmailProducer.startWithValues { (correct) in self.emailTextField.textColor = correct ? UIColor.gray : UIColor.red } // lang nghe tin hieu correctInputProducer //registerButton.reactive.isEnabled <~ viewModel.correctInputProducer //or viewModel.correctInputProducer.startWithValues({ correct in self.registerButton.isEnabled = correct }) // lang nghe tin hieu correctPasswordProducer viewModel.correctPasswordProducer.startWithValues { (correct) -> () in let backgroundColor = correct ? UIColor.gray : UIColor.red self.passwordTextField.textColor = backgroundColor self.passwordAgainTextField.textColor = backgroundColor } //lang nghe property useCreditCard --> producer viewModel.useCreditCard.producer.startWithValues { (useCard) -> () in self.tableView.beginUpdates() self.tableView.endUpdates() } //lang nghe property cardStatus --> producer viewModel.cardStatus.producer.startWithValues { (status) -> () in switch status { case .notVerified: self.cardStatusLabel.text = "Card has not been verified yet" self.activityIndicator.isHidden = true self.verifyCardButton.isHidden = false case .verifying: self.cardStatusLabel.text = "Card is currently being verified" self.activityIndicator.isHidden = false self.verifyCardButton.isHidden = true case .verified: self.cardStatusLabel.text = "Card is verified" self.activityIndicator.isHidden = true self.verifyCardButton.isHidden = true case .denied: self.cardStatusLabel.text = "Card is denied" self.activityIndicator.isHidden = true self.verifyCardButton.isHidden = false } }
Quan trọng vẫn là kết quả nó sẽ làm những gì!
- Nhiều lắm, mình cũng không biết hết nhưng trước hết nó hết sức là clean code.
- Thuận lợi phát triển theo mô hình MVVM và MVVM-C(binding data)
- nó đã clean code rồi thì -> dễ maintain
Tham khảo tại đây ReactiveCocoa Không liên quan mấy nhưng đây là link Demo RxCocoa nói chung cũng thuộc FRP
Kết Thực ra trong project demo mình đã comment rất rõ ràng và dễ đọc, mình mới tìm hiểu về Reactive Cocoa thôi cũng chưa nắm được hết mọi thứ trong Reactive Cocoa, tìm được 1 project Demo về Reactive Cocoa khó quá nên mình quyết định viết 1 bài Demo để các bạn tham khảo, kiến thức về FPR đã được rất nhiều các anh/chị đi trước viết và đây là sức mạnh nho nhỏ của FRP mà mình muốn giới thiệu,cám ơn các bạn đã đọc bài viết của mình.