我想用RxSwift編寫一個MVVM,並比較我在Objective-C中使用的ReactiveCocoa中的內容,但以正確的方式編寫我的服務有點困難。RxSwift正確的方法
一個例子是一個登錄服務。
隨着ReactiveCocoa(Objective-C的),我的代碼是這樣的:
// ViewController
// send textfield inputs to viewmodel
RAC(self.viewModel, userNameValue) = self.fieldUser.rac_textSignal;
RAC(self.viewModel, userPassValue) = self.fieldPass.rac_textSignal;
// set button action
self.loginButton.rac_command = self.viewModel.loginCommand;
// subscribe to login signal
[[self.viewModel.loginResult deliverOnMainThread] subscribeNext:^(NSDictionary *result) {
// implement
} error:^(NSError *error) {
NSLog(@"error");
}];
和我的視圖模型應該是這樣的:
// valid user name signal
self.isValidUserName = [[RACObserve(self, userNameValue)
map:^id(NSString *text) {
return @(text.length > 4);
}] distinctUntilChanged];
// valid password signal
self.isValidPassword = [[RACObserve(self, userPassValue)
map:^id(NSString *text) {
return @(text.length > 3);
}] distinctUntilChanged];
// merge signal from user and pass
self.isValidForm = [RACSignal combineLatest:@[self.isValidUserName, self.isValidPassword]
reduce:^id(NSNumber *user, NSNumber *pass){
return @([user boolValue] && [pass boolValue]);
}];
// login button command
self.loginCommand = [[RACCommand alloc] initWithEnabled:self.isValidForm
signalBlock:^RACSignal *(id input) {
return [self executeLoginSignal];
}];
現在RxSwift我寫的一樣:
// ViewController
// initialize viewmodel with username and password bindings
viewModel = LoginViewModel(withUserName: usernameTextfield.rx_text.asDriver(), password: passwordTextfield.rx_text.asDriver())
// subscribe to isCredentialsValid 'Signal' to assign button state
viewModel.isCredentialsValid
.driveNext { [weak self] valid in
if let button = self?.signInButton {
button.enabled = valid
}
}.addDisposableTo(disposeBag)
// signinbutton
signInButton.rx_tap
.withLatestFrom(viewModel.isCredentialsValid)
.filter { $0 }
.flatMapLatest { [unowned self] valid -> Observable<AutenticationStatus> in
self.viewModel.login(self.usernameTextfield.text!, password: self.passwordTextfield.text!)
.observeOn(SerialDispatchQueueScheduler(globalConcurrentQueueQOS: .Default))
}
.observeOn(MainScheduler.instance)
.subscribeNext {
print($0)
}.addDisposableTo(disposeBag)
我改變按鈕狀態,因爲我不能這樣工作:
viewModel.isCredentialsValid.drive(self.signInButton.rx_enabled).addDisposableTo(disposeBag)
和我的ViewModel
let isValidUser = username
.distinctUntilChanged()
.map { $0.characters.count > 3 }
let isValidPass = password
.distinctUntilChanged()
.map { $0.characters.count > 2 }
isCredentialsValid = Driver.combineLatest(isValidUser, isValidPass) { $0 && $1 }
和
func login(username: String, password: String) -> Observable<AutenticationStatus>
{
return APIServer.sharedInstance.login(username, password: password)
}
我使用的驅動程序,因爲它換了一些不錯的功能,如:catchErrorJustReturn(),但我真的不喜歡我正在這樣做:
1)我必須發送用戶名和密碼字段作爲參數到viewModel(順便說一下,的更容易解決)
2)我不喜歡我的viewController完成所有的工作,當登錄按鈕被點擊時,viewController不需要知道它應該調用哪個服務來獲得登錄訪問,它是一個viewModel作業。
3)我無法訪問訂閱以外的用戶名和密碼的存儲值。
有沒有不同的方法來做到這一點?你好嗎?Rx'ers做這種事情?非常感謝。