1、註冊控制器ide
控制器上的一個屬性post
@property (weak, nonatomic) IBOutlet UIBarButtonItem *signInBtn;
在fetch
viewDidLoad
方法中寫入atom
self.signInBtn.rac_command = self.viewModel.executeSignInCommand;
self.viewModel是控制器上的一個viewModelspa
@property (nonatomic, weak) MSFAuthorizeViewModel *viewModel;
其上有個屬性code
@property (nonatomic, strong) RACCommand *executeSignInCommand;
這個executeSignInCommand在viewModel的初始化方法中生成blog
- (instancetype)initWithServices:(id <MSFViewModelServices>)services { self = [super init]; if (!self) { return nil; } _services = services; ..... _executeSignInCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { self.loginType = MSFLoginSignIn; [self.services presentViewModel:self]; return [RACSignal return:nil]; }]; .... }
而presentViewModel:僅僅只是一個協議,沒有實現,有個樣本input
- (void)presentViewModel:(id)viewModel { id viewController; if ([viewModel isKindOfClass:MSFAuthorizeViewModel.class]) { MSFAuthenticateViewController *loginViewController = [[MSFAuthenticateViewController alloc] initWithViewModel:viewModel]; viewController = [[UINavigationController alloc] initWithRootViewController:loginViewController]; UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(UIScreen.mainScreen.bounds), 20)]; view.backgroundColor = UIColor.blackColor; [[(UIViewController *)viewController view] addSubview:view]; } else { NSLog(@"an unknown ViewModel was present!"); } [self.navigationController presentViewController:viewController animated:YES completion:nil]; }
再看看控制器的其餘屬性同步
@property (nonatomic, weak) IBOutlet UITextField *usernameF; @property (nonatomic, weak) IBOutlet UITextField *captchaF; @property (nonatomic, weak) IBOutlet UITextField *passwordF;
也是在viewDidLoad中處理的,方法viewWillAppear有一執行就會有一個信號發送,控制器訂閱了這個信號,並在收到信號後,執行操做:string
把控件上的文件賦值給viewModel上的對應的屬性。
@weakify(self) [[self rac_signalForSelector:@selector(viewWillAppear:)] subscribeNext:^(id x) { @strongify(self) self.viewModel.username = self.usernameF.text; self.viewModel.password = self.passwordF.text; self.viewModel.loginType = MSFLoginSignUp; }];
固然,相應的textField文本改變時,咱們也會處理
輸入的文本長度超過規定的長度,則進行截取而後放置到field中,再賦值給viewModel中對應的屬性
[self.username.rac_textSignal subscribeNext:^(id x) { @strongify(self) if ([x length] > MSFAuthorizeUsernameMaxLength) self.username.text = [x substringToIndex:MSFAuthorizeUsernameMaxLength]; self.viewModel.username = self.username.text; }];
密碼輸入框也是
[self.password.rac_textSignal subscribeNext:^(id x) { @strongify(self) if ([x length] > MSFAuthorizePasswordMaxLength) self.password.text = [x substringToIndex:MSFAuthorizePasswordMaxLength]; self.viewModel.password = self.password.text; }];
還有密碼field在按下下一步的return鍵時,就至關於按下了註冊按鈕,此時就會調用viewModel上的executeSignUp命令
[self.password.rac_keyboardReturnSignal subscribeNext:^(id x) { @strongify(self) [self.viewModel.executeSignUp execute:nil]; }];
這個命令也是跟登陸命令同樣在同一個方法中初始化
_executeSignUp = [[RACCommand alloc] initWithEnabled:self.signUpValidSignal signalBlock:^RACSignal *(id input) { @strongify(self) return [self executeSignUpSignal]; }];
固然,這個命令要受到能點不能點擊的影響self.signUpValidSignal,當用戶名和密碼還有驗證碼都有輸入的狀況下,就會調用自身上的一個excuteSignUpSignal
- (RACSignal *)signUpValidSignal { return [RACSignal combineLatest:@[ RACObserve(self, username), RACObserve(self, password), RACObserve(self, captcha), ] reduce:^id(NSString *username, NSString *password, NSString *captcha){ return @(username != nil && password != nil && captcha != nil); }]; }
忽然間感受這裏好複雜再也不深究,先看其餘的
- (RACSignal *)executeSignUpSignal { if (![self.username isMobile]) { return [RACSignal error:[self.class errorWithFailureReason:@"請填寫真實的手機號碼"]]; } else if (![self.password isPassword]) { return [RACSignal error:[self.class errorWithFailureReason:@"請填寫8到16位數字和字母組合的密碼"]]; } else if (![self.captcha isCaptcha]) { return [RACSignal error:[self.class errorWithFailureReason:@"請填寫驗證碼"]]; } else if (!self.agreeOnLicense) { return [RACSignal error:[self.class errorWithFailureReason:@"請閱讀註冊協議"]]; } MSFUser *user = [MSFUser userWithServer:MSFServer.dotComServer]; return [[MSFClient signUpAsUser:user password:self.password phone:self.username captcha:self.captcha] doNext:^(MSFClient *client) { _signInValid = YES; [self.services setHttpClient:client]; [[client fetchUserInfo] subscribeNext:^(MSFUser *x) { [client.user mergeValueForKey:@keypath(x.personal) fromModel:x]; [client.user mergeValueForKey:@keypath(x.professional) fromModel:x]; [client.user mergeValueForKey:@keypath(x.contacts) fromModel:x]; [client.user mergeValueForKey:@keypath(x.profiles) fromModel:x]; [client.user mergeValueForKey:@keypath(x.insurance) fromModel:x]; }]; }]; }
有個顯示密碼與隱藏密碼的按鈕
[[self.showPasswordButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { @strongify(self) self.showPasswordButton.selected = !self.showPasswordButton.selected; NSString *text = self.password.text; self.password.text = text; self.password.enabled = NO; [self.password setSecureTextEntry:!self.showPasswordButton.selected]; self.password.enabled = YES; [self.password becomeFirstResponder]; }];
再看看驗證碼輸入框,長度限制、截取、同步viewModel的對應屬性
[self.captcha.rac_textSignal subscribeNext:^(id x) { @strongify(self) if ([x length] > MSFAuthorizeCaptchaMaxLength) self.captcha.text = [x substringToIndex:MSFAuthorizeCaptchaMaxLength]; self.viewModel.captcha = self.captcha.text; }];
同步viewModel上的命令
self.sendCaptchaButton.rac_command = self.viewModel.executeCaptcha;
執行命令時的操做,鍵盤釋放,SVProgressHUD顯示正在獲取驗證碼
[self.sendCaptchaButton.rac_command.executionSignals subscribeNext:^(RACSignal *captchaSignal) { @strongify(self) [self.view endEditing:YES]; [SVProgressHUD showWithStatus:@"正在獲取驗證碼" maskType:SVProgressHUDMaskTypeClear]; [captchaSignal subscribeNext:^(id x) { [SVProgressHUD dismiss]; }]; }];
當這個命令有錯誤時的回調
[self.sendCaptchaButton.rac_command.errors subscribeNext:^(NSError *error) {
[SVProgressHUD showErrorWithStatus:error.userInfo[NSLocalizedFailureReasonErrorKey]];
}];
同理,提交、註冊按鈕也是相似 的,先綁定命令
self.commitButton.rac_command = self.viewModel.executeSignUp;
而後,執行命令的回調,釋放鍵盤,提示正在註冊...而後會發送一個通知,沒看到這個是什麼意思 [signUpSignal subscribeNext:^(id x) {
[self.commitButton.rac_command.executionSignals subscribeNext:^(RACSignal *signUpSignal) { @strongify(self) [self.view endEditing:YES]; [SVProgressHUD showWithStatus:@"正在註冊..." maskType:SVProgressHUDMaskTypeClear]; [signUpSignal subscribeNext:^(id x) { [[NSNotificationCenter defaultCenter] postNotificationName:@"MSFREQUESTCONTRACTSNOTIFACATION" object:nil]; [SVProgressHUD dismiss]; }]; }];
收到錯誤時的信號
[self.commitButton.rac_command.errors subscribeNext:^(NSError *error) {
[SVProgressHUD showErrorWithStatus:error.userInfo[NSLocalizedFailureReasonErrorKey]];
}];
驗證碼倒計時Label
@property (nonatomic, weak) IBOutlet UILabel *counterLabel;
viewDidLoad中操做,viewModel上的對應的屬性變動時,會同步到這個控制器上的label來
RAC(self, counterLabel.text) = RACObserve(self, viewModel.counter);