Reactive Cocoa实践举例

这篇文章主要通过举例说明Reactive Cocoa的使用方法,所举的例子都比较典型和实用,在实际的项目中都会有所涉及,也希望大家可以举一反三。

一.输入框输入11位合法手机号,获取验证码按钮才可用,号码不合法,按钮不可用,点击按钮,倒计时60s后,才可以再次可用,在等待期间,无论输入框输入的是否再次合法,获取验证码按钮都是不可用的。

RACSignal *validPhone = [self.phoneTextField.rac_textSignal map:^id(NSString *text) {

return @([RegFun checkPhoneLegal:text]);

}];

self.sendCodeBtn.rac_command = [[RACCommand alloc] initWithEnabled: validPhone signalBlock:^RACSignal *(id input) {

return [self sendCodeSingal];

}];  // validPhone控制点击的block是否可以执行,同时也控制了按钮的状态,当点击后,只要block返回的signal还没有sendCompleted,这时候你无论怎么输入字符还是做什么操作,按钮都是不可用的,这样就解决了,正在请求接口,再输入字符,按钮又变成可用的问题。

-(RACSignal *)sendCodeSingal{

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

[[AuthorizeURL sharedInstance] startWithM:URL_M_User andWithA:@"sendSmsCode" andOtherDic:dic andIsNeedWaitingView:YES andIsNeedPopMessageWhenSuccess:YES andIsNeedCallBlockWhenNoNetwork:YES andSuccessBlock:^(id responseObj, BOOL isSuccess) {

if (isSuccess) {

self.leftTime = 60;

RACSignal *sendCodeEnableSignal = [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] take:self.leftTime]; //每1s执行一次

[sendCodeEnableSignal subscribeNext:^(id x) {

self.leftTime --;

[self.sendCodeBtn setTitle:[NSString stringWithFormat:@"等待(%d秒)",self.leftTime] forState:UIControlStateDisabled];

if (self.leftTime == 0) {  //时间为0时,才发送信号,让按钮可用。

[self.sendCodeBtn setTitle:@"发送验证码" forState:UIControlStateDisabled];  //字符归位,不然下次就会显示等待0.

[subscriber sendNext:@(isSuccess)];

[subscriber sendCompleted];

}

}];

}else{

[subscriber sendNext:@(isSuccess)];

[subscriber sendCompleted];

}

}];

return nil;

}];

}

二.通过代码直接textView.text = @”this is a example”,也要达到rac_textSignal一样的信号效果。

//直接给值的话,rac_textSignal是不调用的,必须通过观察,然后,输入的时候,观察是不调用的,两者合并,有一者触发即可。

RACSignal *validUserName = [[RACSignal merge:@[self.userNameTextField.rac_textSignal, RACObserve(self.userNameTextField, text)]] map:^id(NSString *text) {

return @(text.length > 0);

}];

三.非常解耦的控制底部tabbar小红点和各个子小红点的显示和隐藏。

RACSignal *myMessageSignal =  RACObserve(self, myMessageCircleNum);

RACSignal *groupMessageSignal = RACObserve(self, groupMessageNum);

RACSignal *mySysMessageSignal = RACObserve(self, mySysMessageCircleNum);

//这三个数值控制三个子小红点的显示隐藏,监听他们值的改变,有改变,就发通知,去刷页面,去控制子小红点的显示和隐藏。

[groupMessageSignal subscribeNext:^(NSNumber *x) {

[[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_CircleType object:@(8)]; //发送通知,其他页面只要有监听,就可以刷新页面,和控制子其对应的子小红点的显示和隐藏。

[self saveToLocalWithType:8];  //存本地

}];

RACSignal *helloCircleSignal = [RACSignal combineLatest:@[myMessageSignal,mySysMessageSignal,groupMessageSignal] reduce:^id(NSNumber *myMessage,NSNumber *mySysMessage,NSNumber *groupMessage){

return @(myMessage.intValue == 0 && mySysMessage.intValue == 0 && groupMessage.intValue == 0);  //当三者都为0,证明他们对应的子小红点都隐藏了,那么底部的小红点也才消失。

}];

[helloCircleSignal subscribeNext:^(NSNumber *x) {

XAppDelegate.homeVC.helloVCRedCircle.hidden = x.boolValue;

}];  //三者只要有一者的值改变,就会触发这个合并的信号,就可以刷新底部小红点的显示。

四.监听登陆状态的改变,从登陆到登出,从登出到登陆,状态的改变需要刷新页面和处理数据

//在登陆和登出的地方,会发出对应的通知,各个页面只要监听即可。

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:KNOTIFICATION_USERLOGINCHANGE object:nil] subscribeNext:^(NSNotification *notification) {

BOOL isinLogin = [notification.object boolValue];

if (isinLogin) { //从未登录到登录。

[self handleWhenLoginIn];

}else{  //从登录到未登录。

[self handleWhenLogout];

}

}];

五.替代各种delegate,让代码更集中,更易读

UIActionSheet* sheet = [[UIActionSheet alloc]initWithTitle:nil delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"拍照",@"从相册中选取", nil];

[[sheet rac_buttonClickedSignal] subscribeNext:^(NSNumber* number) {   // UIActionSheet的delegate

UIImagePickerController* controller = nil;

int num = number.intValue;

if(num == 0) { //拍照

controller = [CameraAndPhoto getCameraPickerControllerAndIsFront:YES];

}

if(num == 1) { //相册

controller = [CameraAndPhoto getPhotoLibarayPickerController];

}

if ((num == 0 || num == 1) && controller) {

[self presentViewController:controller animated:YES completion:nil];

[[controller rac_imageSelectedSignal] subscribeNext:^(NSDictionary *info) {

// UIImagePickerController点击确定后调用

[controller dismissViewControllerAnimated:YES completion:^{

UIImage *portraitImg = [info objectForKey:@"UIImagePickerControllerOriginalImage"];

VPImageCropperViewController *imgCropperVC = [[VPImageCropperViewController alloc] initWithImage:portraitImg cropFrame:CGRectMake(0, (kScreen_Height - kScreen_Width)/2, kScreen_Width,kScreen_Width) limitScaleRatio:4.0 andIsNeedCircle:YES];

imgCropperVC.delegate = self;  //delegate还是要赋值的。

[[self rac_signalForSelector:@selector(imageCropper:didFinished:) fromProtocol:@protocol(VPImageCropperDelegate)] subscribeNext:^(RACTuple *tuple) {  //图片裁切VC的delegate,本来是要散落在self页面,现在集成到这里,图片裁切确定后的回调

[imgCropperVC dismissViewControllerAnimated:YES completion:^{

UIImage *editedImage = tuple.second;

}];

}];

[[self rac_signalForSelector:@selector(imageCropperDidCancel:) fromProtocol:@protocol(VPImageCropperDelegate)] subscribeNext:^(RACTuple *tuple){  //图片裁切VC的delegate,图片裁切取消后的回调

[imgCropperVC dismissViewControllerAnimated:YES completion:^{

}];

}];

[self presentViewController:imgCropperVC animated:YES completion:nil];

}];

} completed:^{  // UIImagePickerController点击取消后调用

[controller dismissViewControllerAnimated:YES completion:^(){   //相当于cancel

}];

}];

}

}];

[sheet showInView:self.view];

六.信号混合使用,RACSubject的使用,将非RAC带入RAC。

self.textSingal = [RACSubject subject];  //先声明

self.publishBtn.rac_command = [[RACCommand alloc] initWithEnabled:self.textSingal signalBlock:^RACSignal *(id input) {

if (self.imageHasUploadToUpYun) {

return [self tellServerSignalWith:nil];  //图片已经上传成功了,如果告诉我们的服务器失败了,第二次点击按钮的时候,不用重新上传图片,直接将地址告诉我们的服务器。

}else{

return [self submitSignal];  //开始上传图片

}

}];

[self.textSingal sendNext:[self isValid]]; //[self isValid]函数返回的NSNumber的值就是通过非RAC的普通代码计算得来,来控制publishBtn的enable状态,这句话可以放在其他需要控制按钮状态的地方,比如选择图片后,调用一下,初始化的使用调用一下。

//代码的例子是先把图片上传到云服务器,上传成功后,再将取得的图片地址告诉自己的服务器。

-(RACSignal *)submitSignal{

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

self.uploadImageManager = [[UploadImageManager alloc] initWithMultiImageArray:self.multiPhotoVCManager.lastUploadImageArray andNeedWait:YES andMultiPhotoVCManager:self.multiPhotoVCManager andSuccessBlock:^(BOOL isAllComplete, NSArray *imageSrcArray, NSArray *hasSuccessObjArray, NSArray *hasFailedObjArray) {

if (imageSrcArray.count > 0) {  //开始告诉我们自己的服务器。

self.imageHasUploadToUpYun = YES;  //这个时候,已经到云了。除非再动图片了,否则如果接下去告诉我们自己的服务器失败后,也不用再重新上传图片。

RACSignal *temp = [self tellServerSignalWith:subscriber];  //此时信号为冷的,将上传到云的信号的subscriber传递到告诉服务器的函数,这样才能在告诉服务器的信号完成后,也让上传到云的信号能够完成,形成回路。

[temp subscribeNext:^(id x) {  //调用一下,激活告诉服务器的信号。

}];

}else{  //上传完成了,一张都没有成功。

[subscriber sendNext:@(0)];

[subscriber sendCompleted];

}

return nil;

}];

}

//将图片地址告诉我们自己的服务器

-(RACSignal *)tellServerSignalWith:(id<RACSubscriber>)subscriber1{

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

[[AuthorizeURL sharedInstance] startWithM:URL_M_Daily andWithA:@"add" andOtherDic:dict andIsNeedWaitingView:YES andIsNeedPopMessageWhenSuccess:YES andIsNeedCallBlockWhenNoNetwork:YES andSuccessBlock:^(id responseObj, BOOL isSuccess) {

[subscriber sendNext:@(isSuccess)];   //让告诉我们服务器图片地址的信号结束

[subscriber sendCompleted];

[subscriber1 sendNext:@(isSuccess)];  //让云服务器的信号结束

[subscriber1 sendCompleted];

}];

return nil;

}];

}

时间: 2024-08-24 21:24:23

Reactive Cocoa实践举例的相关文章

RAC(Reactive Cocoa)常见的类

导入ReactiveCocoa框架 在终端,进入Reactive Cocoa文件下 创建podfile 打开该文件 并配置 use_frameworks! pod ’ReactiveCocoa’, ’~>4.0.2-alpha-1' 安装pod install --no-repo-update 遇到头文件导入不进去,可以将头文件放到全局的.h文件中 ReactiveCocoa常见的类 RACSignal:信号类;RACSubscriber是协议 简介 有数据产生时就会使用RACSignal类 默

IOS开发之OC篇-响应式编程Reactive Cocoa

一.Reactive Cocoa 介绍 Reactive Cocoa 是 iOS 开发的一个 "重量级" 框架 高大上的概念:响应式编程 核心概念:信号 Signal 官方网站:https://github.com/ReactiveCocoa/ReactiveCocoa 二.相关概念 1> 响应式编程 举个栗子,在一般程序开发时  a = b + c , 赋值之后 b 或者 c 的值变化后,a 的值不会跟着变化, 如果使用响应式编程,目标就是,如果 b 或者 c 的数值发生变化,

Reactive Cocoa 响应式编程开发实例讲解-中篇

上一篇文章作为开门篇讲述了Cocoa Reactive概述. 这里我们详细介绍一下CocoaReative在代码中的应用. 网上好多blog有人形容CocoaReative 中 signals是插座或者水龙头,感觉不是很好理解.我举个更贴近生活的,用电话订菜(餐馆是Signals,电话订阅是SubScriberNext). 1.概述 Create一个Signal我们视为是一个支持电话订餐的餐馆,他们有很多菜,油盐酱醋就更不用说,当一个电话打进来首先,这个Signal就开始执行,等菜做好了,菜馆要

iOS应用开发最佳实践:编写高质量的Objective-C代码

本文转载至 http://www.cocoachina.com/industry/20131129/7445.html 点标记语法 属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问,其他的情况使用方括号标记语法. 良好的风格 : view.backgroundColor = [UIColor orangeColor]; [UIApplication sha “” 阅读器 本文由“海水的味道"编译 点标记语法 属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问

完美CSS文档的8个最佳实践

  在css的世界,文档没有被得到充分的利用.由于文档对终端用户不可见,因此它的价值常常被忽视.另外,如果你第一次为css编写文档,可能很难确定哪些内容值得记录,以及如何能够高效完成编写. 然而,为CSS编写文档可以为你的项目提供很多好处:促进更好的代码实践.降低新员工的上手难度.在本文中,我将说明编写CSS文档的优点,并分享我认为的最佳实践.让文档为你工作,而不是阻碍你的工作. 1. 制定基本规则 当你和你的团队不清楚CSS文档具体需要编写哪些内容.文档应该如何工作时,你很难跟上编写CSS文档

自己总结的 iOS ,Mac 开源项目以及库,知识点------持续更新

自己在 git  上看到一个非常好的总结的东西,但是呢, fork  了几次,就是 fork  不到我的 git 上,干脆复制进去,但是,也是认真去每一个每一个去认真看了,并且也是补充了一些,感觉非常棒,所以好东西要分享,为啥用 CN 博客,有个好处,可以随时修改,可以持续更新,不用每次都要再发表,感觉这样棒棒的 我们 自己总结的iOS.mac开源项目及库,持续更新.... github排名 https://github.com/trending,github搜索:https://github.

iOS开发 非常全的三方库、插件、大牛博客等等

UI 下拉刷新 EGOTableViewPullRefresh- 最早的下拉刷新控件. SVPullToRefresh- 下拉刷新控件. MJRefresh- 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.具体使用看"使用方法". (国人写) XHRefreshControl- XHRefreshControl 是一款高扩展性.低耦合度的下拉刷新.上提加载更多的组件.(国人写) CBStoreHo

iOS、mac开源项目及库汇总

UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.具体使用看“使用方法”. (国人写) XHRefreshControl – XHRefreshControl 是一款高扩展性.低耦合度的下拉刷新.上提加载更多的组件.(国人写) CBStoreHou

最全面的iOS和Mac开源项目和第三方库汇总

UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.具体使用看“使用方法”. (国人写) XHRefreshControl – XHRefreshControl 是一款高扩展性.低耦合度的下拉刷新.上提加载更多的组件.(国人写) CBStoreHou