函数响应式编程及ReactiveObjC学习笔记 (三)
为什么80%的码农都做不了架构师?>>>
http://www.cnblogs.com/zhouxihi/p/7226917.html
ReactiveObjC UITextView+RACSignalSupport.h
之前讲了RAC如何帮我们实现KVO / 代理 / 事件 / 通知
今天先不去分析它的核心代码, 我们先看看ReactiveObjC库里面一些特别的东西, 如果大家点开ReactiveObjC目录应该会看到很多category, 今天我们先来看看这些
我们先从UITextView+RACSignalSupport.h开始看
#import <UIKit/UIKit.h>@class RACDelegateProxy;
@class RACSignal<__covariant ValueType>;NS_ASSUME_NONNULL_BEGIN@interface UITextView (RACSignalSupport)@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;- (RACSignal<NSString *> *)rac_textSignal;@end
这里有一个属性跟一个方法,
关于RACDelegateProxy这个类的用途大概是把初始化传入的代理绑定或者添加给当前正在处理的信号
给大家一个例子:
#import "ViewController.h"
#import <ReactiveObjC.h>
#import <objc/runtime.h>@interface ViewController ()<UITextViewDelegate>@end@implementation ViewController- (void)viewDidLoad {;[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.// 以UITextViewDelegate来初始化一个RACDelegateProxyRACDelegateProxy *delegateProxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextViewDelegate)];// 注册要实现的方法[[delegateProxyrac_signalForSelector:@selector(textViewDidBeginEditing:)]subscribeNext:^(RACTuple * _Nullable x) {NSLog(@"开始编辑");}];UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];textView.center = self.view.center;textView.backgroundColor = [UIColor greenColor];// 设置代理为我们创建的RACDelegateProxy, 注意要转义不然会有警告textView.delegate = (id<UITextViewDelegate>)delegateProxy;[self.view addSubview:textView];// retain我们创建的delegateProxy, 避免被释放objc_setAssociatedObject(textView, _cmd, delegateProxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end
这个一般是RAC内部使用, 我们比较少用. 另外也只能处理没有返回值的代理方法
可以到UITextview+RACSignalSupport.m里面看看, 也是类似这样用的
- (RACDelegateProxy *)rac_delegateProxy {RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd);if (proxy == nil) {proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextViewDelegate)];objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}return proxy;
}
好了, 现在我们来使用下这个UITextView类别唯一的方法
- (RACSignal<NSString *> *)rac_textSignal;
大家可以看到, 这个方法会返回一个信号 我们可以对他订阅, 试试看
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];textView.center = self.view.center;textView.backgroundColor = [UIColor greenColor];[self.view addSubview:textView];[[textViewrac_textSignal]subscribeNext:^(NSString * _Nullable x) {NSLog(@"%@", x);}];
运行看看, 当我们在textView中输入文字的时候会打印:
2017-07-23 22:41:42.841 RAC[70053:14036438] 1 2017-07-23 22:41:43.353 RAC[70053:14036438] 11 2017-07-23 22:41:44.031 RAC[70053:14036438] 111
所以这个x就是Textview的内容了.
下面我们看看
UITextField+RACSignalSupport.h
#import <UIKit/UIKit.h>@class RACChannelTerminal<ValueType>;
@class RACSignal<__covariant ValueType>;NS_ASSUME_NONNULL_BEGIN@interface UITextField (RACSignalSupport)- (RACSignal<NSString *> *)rac_textSignal;- (RACChannelTerminal<NSString *> *)rac_newTextChannel;@endNS_ASSUME_NONNULL_END
这里有两个方法, 我们先看第一个rac_textSignal
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];textField.center = self.view.center;textField.backgroundColor = [UIColor yellowColor];[[textFieldrac_textSignal]subscribeNext:^(NSString * _Nullable x) {NSLog(@"%@", x);}];[self.view addSubview:textField];
运行看看, 我们输入数字的时候会打印内容:
2017-07-23 22:55:45.686 RAC[70205:14118946] 1 2017-07-23 22:55:46.139 RAC[70205:14118946] 11 2017-07-23 22:55:46.798 RAC[70205:14118946] 111
然后我们看看另外一个方法
- (RACChannelTerminal<NSString *> *)rac_newTextChannel;
这里涉及到了一个类RACChannelTerminal, 我们点进去看看这个类
@interface RACChannelTerminal<ValueType> : RACSignal<ValueType> <RACSubscriber>- (instancetype)init __attribute__((unavailable("Instantiate a RACChannel instead")));// Redeclaration of the RACSubscriber method. Made in order to specify a generic type.
- (void)sendNext:(nullable ValueType)value;@end
可以看到它是一个RACSignal的子类, 我们先调用看看这个方法
[[textFieldrac_newTextChannel]subscribeNext:^(NSString * _Nullable x) {NSLog(@"%@", x);}];
效果跟rac_textSignal一样, 那么它有什么特别的用法呢
它的作用是做双向绑定 关于什么是双向绑定呢? 给大家一个简单的例子:
UITextField *textFieldA = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];textFieldA.center = self.view.center;textFieldA.backgroundColor = [UIColor yellowColor];[self.view addSubview:textFieldA];UITextField *textFieldB = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];textFieldB.center = CGPointMake(self.view.center.x, self.view.center.y + 50);textFieldB.backgroundColor = [UIColor yellowColor];[self.view addSubview:textFieldB];RACChannelTerminal *terminalA = [textFieldA rac_newTextChannel];RACChannelTerminal *terminalB = [textFieldB rac_newTextChannel];[terminalA subscribe:terminalB];[terminalB subscribe:terminalA];
运行可以看到, 改变textFieldA的值textFieldB的值也会跟着改变, 反过来也一样.
这里如果要实现双向绑定, 其实还有一个简单的方法:
RACChannelTo(textFieldA, text) = RACChannelTo(textFieldB, text);
大家可以试试看.
如果我们不仅仅想让两个绑定对象之间的值简单的相等而已呢? 比如textFieldA的值是123的时候textFieldB的值要为321要怎么处理呢?
这里我们先说一个一会用到的方法: map
map方法,将会创建一个和原来一模一样的信号,只不过新的信号传递的值变为了block(value)。
[[[textFieldrac_textSignal]map:^id _Nullable(NSString * _Nullable value) {if ([value isEqualToString:@"11"]) {return @"1";} else {return @"0";}}] subscribeNext:^(id _Nullable x) {NSLog(@"%@", x);}];
运行看看, 当我们输入1, 会打印0, 输入11的时候会打印1, 这里就是把传递的值从textField的text转变成为我们的1 和 0;
然后有个特别的地方, 加入我们知道传递的值的类型, 我们就可以直接把后面订阅的block里面的参数类型直接改成我们知道的类型
例如把id改为NSString *运行结果也是一样的, 这个是RAC一个比较特别的地方
那么要实现上面的123 到 321可以这样写:
RACChannelTerminal *terminalA = [textFieldA rac_newTextChannel];RACChannelTerminal *terminalB = [textFieldB rac_newTextChannel];[[terminalAmap:^id _Nullable(id _Nullable value) {if ([value isEqualToString:@"123"]) {return @"321";}return value;}]subscribe:terminalB];[terminalB subscribe:terminalA];
大家可以自己运行看看效果, 当textFieldA输入123的时候textFieldB会变为321
#import <UIKit/UIKit.h>@class RACDelegateProxy;
@class RACSignal<__covariant ValueType>;NS_ASSUME_NONNULL_BEGIN@interface UIActionSheet (RACSignalSupport)@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;- (RACSignal<NSNumber *> *)rac_buttonClickedSignal;@end
下面我们看看
UIActionSheet+RACSignalSupport.h
rac_delegateProxy跟之前textview是一样的用法这里开始就不再解释这类属性了
我们直接试着使用rac_buttonClickedSignal
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"RAC ActionSheet" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"OK" otherButtonTitles:@"Other", nil];[[actionSheetrac_buttonClickedSignal]subscribeNext:^(NSNumber * _Nullable x) {NSLog(@"%@", x);}];[actionSheet showInView:self.view];
运行看看, x是actionSheet上按钮的编号, 我们拿到编号就可以做响应的事件处理了.
UIAlertView+RACSignalSupport.h
@interface UIAlertView (RACSignalSupport)@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;- (RACSignal<NSNumber *> *)rac_buttonClickedSignal;- (RACSignal<NSNumber *> *)rac_willDismissSignal;@endNS_ASSUME_NONNULL_END
它有两个方法, 一个是点击的时候用, 一个是dismiss的时候用
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Alert" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];[[alertrac_buttonClickedSignal]subscribeNext:^(NSNumber * _Nullable x) {NSLog(@"click: x");}];[[alertrac_willDismissSignal]subscribeNext:^(NSNumber * _Nullable x) {NSLog(@"dismiss: %@", x);}];[alert show];
UIControl+RACSignalSupport.h
#import <UIKit/UIKit.h>@class RACSignal<__covariant ValueType>;NS_ASSUME_NONNULL_BEGIN@interface UIControl (RACSignalSupport)- (RACSignal<__kindof UIControl *> *)rac_signalForControlEvents:(UIControlEvents)controlEvents;@endNS_ASSUME_NONNULL_END
只有一个方法, 这个之前讲过是做UIControllerEvent处理的, 再给个例子:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];[button setFrame:CGRectMake(0, 0, 100, 35)];[button setCenter:self.view.center];[button setBackgroundColor:[UIColor yellowColor]];[button setTitle:@"按钮" forState:UIControlStateNormal];[[buttonrac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(__kindof UIControl * _Nullable x) {NSLog(@"点击了按钮");x.backgroundColor = [UIColor redColor];}];[self.view addSubview:button];
UIDatePicker+RACSignalSupport.h
#import <UIKit/UIKit.h>@class RACChannelTerminal<ValueType>;NS_ASSUME_NONNULL_BEGIN@interface UIDatePicker (RACSignalSupport)- (RACChannelTerminal<NSDate *> *)rac_newDateChannelWithNilValue:(nullable NSDate *)nilValue;@endNS_ASSUME_NONNULL_END
它只有一个绑定的方法, 直接给大家一个例子:
大概效果为我们在Controller中添加一个UITextField跟一个UIDatePicker, 然后获取他们的RACChannelTerminal,
将UIDatePicker绑定给UITextField, 当我们滚动datePicker的时候 textField的值会跟着改变
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 160)];datePicker.center = self.view.center;datePicker.backgroundColor = [UIColor redColor];[self.view addSubview:datePicker];UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 180, 35)];textField.center = CGPointMake(self.view.center.x, self.view.center.y - 100);textField.backgroundColor = [UIColor yellowColor];[self.view addSubview:textField];RACChannelTerminal *datePickerTerminal = [datePicker rac_newDateChannelWithNilValue:[NSDate date]];RACChannelTerminal *textFieldTerminal = [textField rac_newTextChannel];[[datePickerTerminalmap:^id _Nullable(id _Nullable value) {NSLog(@"%@", value);NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];return [dateFormatter stringFromDate:value];}]subscribe:textFieldTerminal];
运行截图:
这篇先写到这里, 下次我们再接着看
转载于:https://my.oschina.net/huqiji/blog/1499616
函数响应式编程及ReactiveObjC学习笔记 (三)相关推荐
- iOS 高大上函数响应式编程框架ReactiveCocoa学习笔记1 简介
ReactiveCocoa函数响应式编程 一.简介 ReactiveCocoa(其简称为RAC)是函数响应式编程框架.RAC具有函数式编程和响应式编程的特性.它主要吸取了.Net的 Reactive ...
- Rxswift学习之(一)函数响应式编程思想
Rxswift学习之(一)函数响应式编程思想 1. 函数响应式编程思想必备基本概念简介 2. iOS中三种编程思想:链式.函数式和响应式编程 2.1 链式编程 2.2 函数式编程 2.3 响应式编程 ...
- Android什么是函数,什么是函数响应式编程(JavaAndroid版本)
什么是函数响应式编程(Java&Android版本) 函数响应式编程(FRP)为解决现代编程问题提供了全新的视角.一旦理解它,可以极大地简化你的项目,特别是处理嵌套回调的异步事件,复杂的列表过 ...
- 响应式编程框架ReactiveCocoa学习——框架概览
这篇博客将会继续翻译RAC的官方文档Framework Overview. 主要是对RAC这和框架进行概览的介绍和学习.同时也可以参考我前面的两篇翻译<响应式编程框架ReactiveCocoa学 ...
- 什么是函数响应式编程?
什么是函数响应式编程? 响应式编程思想为体,函数式编程思想为用.首先我们要来了解什么是函数式编程和响应式编程. 什么是函数式编程? 顾名思义,函数式编程就是用函数来解决问题的编程方式,几乎任何一门语言 ...
- 【iOS架构】iOS ReactiveCocoa函数响应式编程
声明式编程 声明式编程(declarative programming)是一种编程范型,与命令式编程相对立.它描述目标的性质,让电脑明白目标,而非流程.声明式编程不用告诉电脑问题领域,从而避免随之而来 ...
- Android函数响应式编程——RxJava最快速度入门
gradle // RxJava compile 'io.reactivex:rxjava:1.2.0' compile 'io.reactivex:rxandroid:1.2.1' 创建Observ ...
- Android函数响应式编程——必学的RxJava变换操作符map、flatMap、cast、concatMap、flatMapIterable、buffer、groupBy
gradle // RxJava compile 'io.reactivex:rxjava:1.2.0' compile 'io.reactivex:rxandroid:1.2.1' 变换操作符:对被 ...
- 编程范式:函数式编程防御式编程响应式编程契约式编程流式编程
不长的编码生涯,看到无数概念和词汇:面向对象编程.过程式编程.指令式编程.函数式编程.防御式编程.流式编程.响应式编程.契约式编程.进攻式编程.声明式编程--有种生无可恋的感觉. 本文试图加以汇总和整 ...
- [iOS] 响应式编程开发-ReactiveCocoa(一)
什么是响应式编程 响应式编程是一种面向数据流和变化传播的编程范式.这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播. 例如,在命令式编程环境中 ...
最新文章
- ubuntu如何修改字符集编码
- OpenCV3.0中的图像金字塔与图片尺寸缩放
- 方案接口服务器问题记录
- python调用外部程序 退出_2019-09-09 python调用外部程序
- Pytorch教程(十八)tensor的保存为csv,并加载
- 周鸿祎:谷歌Chrome不是浏览器
- csv 读写 python_Python CSV读写
- linux nginx 添加插件,linux安装nginx1.9.9实录
- 由DispatcherServlet看spring mvc请求处理过程
- 华为数通ensp命令(三)
- 英语词根词缀+联想法记忆单词
- python哈希类型_Python散列类型和运算符
- 《码农的爱情》第一章又逢情人节
- 博图v15编程手册_西门子博途TIA中文手册.pdf
- Installations
- 出海季,互联网出海锦囊之本地化
- css下拉菜单出现下划线,简单带下划线跟随效果的CSS3下拉菜单特效
- 预备篇 I :范畴与函子
- Android系统Crash/ANR类型弹框
- java视频播放缓冲技术_android -------- VideoCache 视频播放(缓存视频到本地)
热门文章
- STM32启动模式及API(转)
- ssh无密码登录设置
- 介绍PS大局观很不错的转文
- FZU2105 Digits Count(按位建线段树)题解
- System.Web.Helpers.Json 与 Newtonsoft.Json 的性能对比
- Flask项目之手机端租房网站的实战开发(十三)
- python学习-(__new__方法和单例模式)
- 《锋利的jQuery》随笔(一)
- GGally与pairs相关关系图_史上最全(一)
- apollo-配置管理中心-安装