项目中学习ReactiveCocoa的使用方法
一、注册控制器
控制器上的一个属性
@property (weak, nonatomic) IBOutlet UIBarButtonItem *signInBtn;
在
viewDidLoad
方法中写入
self.signInBtn.rac_command = self.viewModel.executeSignInCommand;
self.viewModel是控制器上的一个viewModel
@property (nonatomic, weak) MSFAuthorizeViewModel *viewModel;
其上有个属性
@property (nonatomic, strong) RACCommand *executeSignInCommand;
这个executeSignInCommand在viewModel的初始化方法中生成
- (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:仅仅只是一个协议,没有实现,有个样本
- (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(, , CGRectGetWidth(UIScreen.mainScreen.bounds), )];
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有一执行就会有一个信号发送,控制器订阅了这个信号,并在收到信号后,执行操作:
把控件上的文件赋值给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);
项目中学习ReactiveCocoa的使用方法的更多相关文章
- SuperDiamond在JAVA项目中的三种应用方法实践总结
SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...
- swift项目中使用OC/C的方法
假如有个OC类OCViewController : UIViewController类里有两个方法 //swift调用oc或c的混编是比较常用的,反过来的调用很少.这里只写了swift调用oc和c的方 ...
- web项目中获取各种路径的方法
~Apple web项目中各种路径的获取 1.可以在servlet的init方法里 String path = getServletContext().getRealPath("/&qu ...
- 【从业余项目中学习2】C# 实现调用Matlab函数(Visual Studio:2008, Matlab:R2009a)
最近正在给客户做的个人项目,要求实现C#与Matlab之间的调用,即C# winform界面收集用户输入的参数,将参数传递给Matlab的算法计算,Matlab函数返回的结果显示在winform界面上 ...
- angular6项目中使用echarts图表的方法(有一个坑,引用报错)
1.安装相关依赖(采用的webpack) npm install ecahrts --save npm install ngx-echarts --save 2.angular.json 配置echa ...
- 【从业余项目中学习1】C# 实现XML存储用户名密码(MD5加密)
最近在写一个C#的项目,用户需求是实现Winform的多文档界面与Matlab算法程序之间的交互.做了一段时间发现,这既能利用业余时间,实战中也可学习一些技术,同时刚毕业也增加一份收入.所以后面会不断 ...
- 从项目中学习HTML+CSS
最近由于工作原因以及自己的懈怠,已经很久都没有更新过博客了.通过这段时间,我发现坚持一件事情是真的很难,都说万事开头难,但是在放弃这件事上好像开头了后面就顺理成章的继续下去了.中间即使不怎么情愿也在努 ...
- [冲昏头脑]IDEA中的maven项目中学习log4j的日志操作
第一,你要有log4j的对应的包,由于我用的maven,所以直接在pom.xml文件依赖下载则可,如你尚为有此包,请自行百度下载导入,或上http://www.mvnrepository.com/搜索 ...
- 在项目中添加ReactiveCocoa #安装与配置
这是对官方教程的补充 To add RAC to your application: Add the ReactiveCocoa repository as a submodule of your a ...
随机推荐
- Apache查看连接数和限制当前的连接数
在wamp环境下查看apche连接数和限制当前的连接数 httpd_mpm.conf文件在你apache安装上当的\\conf\\extra中,还在就是在要apache httpd.conf中把#In ...
- java继承(implements与extends)总结
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/weixin_39938767/article/details/80056922 关键字impl ...
- C#经纬度加减运算(度°分′秒″格式)
经度是分和秒是按60进位,如果要做运算第一步就是转换成浮点数,之后就是计算和还原. using System.Text.RegularExpressions; public static double ...
- Codeforces Round #532 (Div. 2) E. Andrew and Taxi(二分+拓扑排序)
题目链接:https://codeforces.com/contest/1100/problem/E 题意:给出 n 个点 m 条边的有向图,要翻转一些边,使得有向图中不存在环,问翻转的边中最大权值最 ...
- PHP流程控制之if语句多种嵌套
王思总同学我们在最开始的故事中讲到了他有两个秘书:一个生活秘书.一个工作秘书. 王思总同学在出行和项目中也是极度有计划性.他给自己的生活秘书和工作秘书分别指派了出差的行程:大理石平台支架 生活上: 先 ...
- web+文件夹上传
一. 大文件上传基础描述: 各种WEB框架中,对于浏览器上传文件的请求,都有自己的处理对象负责对Http MultiPart协议内容进行解析,并供开发人员调用请求的表单内容. 比如: Spring 框 ...
- luogu 3702 [SDOI2017]序列计数 矩阵乘法+容斥
现在看来这道题真的不难啊~ 正着求不好求,那就反着求:答案=总-全不是质数 这里有一个细节要特判:1不是质数,所以在算全不是质数的时候要特判1 code: #include <bits/stdc ...
- QT项目之创建.pri文件
做大项目的时候,有很多.h和.cpp文件,会很繁琐.就需要.pri文件夹,将大项目分解成一个个的子项目,方便理清思绪和后期维护. 废话不多说,直接上过程! 第一步:新建一个项目.如图,选择choose ...
- KMP解决字符串最小循环节相关问题
经典问题 : 给出一个由某个循环节构成的字符串,要你找出最小的循环节,例如 abababab 最小循环节当是 ab ,而类似 abab 也可以成为它的循环节,但并非最短. 分析 : 对于上述问题有两个 ...
- Linux操作系统常用命令合集——第三篇-系统管理操作(25个命令)
1.whoami [命令作用] 显示当前登录有效用户名称 [命令语法] whoami [选项] [常用选项] 无 [参数说明] 用户名称 [命令示例] 显示当前登录有效用户名称 # whoam ...