ReactiveCocoa

RedRain的简书://www.greatytc.com/users/29e03e6ff407/latest_articles

1,ReactiveCocoa

RAC是GitHub开源的框架

2,ReactiveCocoa作用

框架特殊处理了: action, delegate, KVO, callback
如:可以把按钮的target-action聚合在一起, 把UI逻辑处理代码聚合在一起.

3,编程思想

在开发中我们也不能太依赖于某个框架, 否则这个框架不更新了, 导致项目后期无法维护.因此学习一个框架, 还是有必要了解它的编程思想.

3.1面向过程

处理事情以过程为核心, 一步步实现

3.2面向对象

万物皆对象

3.3链式编程思想

将多个操作通过.连接在一起成为一句代码, 使得代码可读性提高.

a(1).b(2).c(3)

特点:

方法的返回值是block, block必须有返回值(对象本身), block参数(需要处理的值)

其中代表的框架 masrony

3.4响应式编程思想

不需要考虑调用顺序, 只需要知道结果, 类似于蝴蝶效应, 产生一个事件,会影响很大东西, 这些事件像流一样的传播出去, 然后影响结果, 借用面向对象的一句话, 万物皆是流.

  • 代表: KVO运用

3.5函数式编程思想

是把操作尽量写成一系列嵌套的函数或者方法调用.

本质:

就是往方法中传入block, 方法中嵌套block调用, 把代码聚合起来管理.

特点:

每个方法有返回值(对象本身), 把函数或者Block当作参数, block参数(需要操作的值) block返回值(操作结果).

代表:

ReactiveCocoa

4.ReactiveCocoa

4.1 RACSignal

有数据产生就会,就使用RACSignal.

  • 1,创建信号(冷信号)
  • 2,订阅信号(热信号)
  • 3,发送信号

4.2 RACDisposable

用于取消订阅或者清理资源, 当信号发送完成或者发送错误时候, 就会自动触发它.

  • 使用场景: 不想监听某个信号时, 可以通过它主动取消订阅信号.

在生成信号的返回值中, 返回RACDisposable对象, 如果创建了这个Block对象, 会在订阅信号后, 调用这个block, 如果在外界强引用这个Disposable对象, 那么不会自动的调用这个Disposable的block, 但是可以通过 signal的 subscribeNext方法的返回对象,disposable主动调用 dispose方法来触发这个block.

4.3 RACSubject

信号提供者, 自己可以充当信号, 又能发送信号.

  • 使用场景: 通常来代替代理, 有了它, 就不必要定义代理了.

RACSubject 发送信号的方式和Signal是不同的, 他的操作步骤中 subscribeNext 只是保存了Nextblock代码. 在subject的SendNext中,会遍历subject中所有的订阅者, 向每一个订阅者发送消息.

4.4 RACReplaySubject

重复提供信号类, RACSubject的子类.
这个类比较特殊,复习时仔细阅读以下1,2,3的解释来理解与其他类的区别

  • 1,创建信号
  • 2,订阅信号: 遍历所有sendNext时保存的值, 向 当前 订阅者去发送数据.
  • 3,发送信号: 先保存这个值, 遍历 所有 订阅者,发送数据.

所有这个类可以 先发送信号, 再订阅信号

4.5 RACTuple

元祖类, 类似NSArray, 用来包装值.

4.6 RACSequence

RAC中的集合类, 用于代替NSArray, NSDictionary, 可以使用它们来快速遍历数组和字典.

  • 使用场景: 字典转模型.

NSArray转换为Sequence
    NSArray *arr = @[@"123",@"123",@"123",@"123"];
    
    [arr.rac_sequence.signal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    

这个方法会直接遍历数组中的每一个值进行订阅. 不需要sendNext方法.


NSDictionary 转换为 Sequence
    NSDictionary *dic = @{@"name":@"123",@"age":@"123"};
    
    [dic.rac_sequence.signal subscribeNext:^(RACTuple *x) {
        
        NSString *key0 = x[0];
        NSString *value0 = x[1];
        NSLog(@"key0:%@ ,value0:%@",key0,value0);

        
        RACTupleUnpack(NSString *key1, NSString *value1) = x;
        NSLog(@"key1:%@ ,value1:%@",key1,value1);
        
        
    }];

打印的信息:

 key0:name ,value0:123
 key1:name ,value1:123
 key0:age ,value0:123
 key1:age ,value1:123
 

应用字典转模型
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"source.plist" ofType:nil];
    NSArray *dicArr = [NSArray arrayWithContentsOfFile:filePath];
    
    NSMutableArray *mArr = [NSMutableArray arrayWithCapacity:3];
    [dicArr.rac_sequence.signal subscribeNext:^(NSDictionary  *x) {
       
        SourceModel *model = [[SourceModel alloc]init];
        model.name = x[@"name"];
        model.age = x[@"age"];
        [mArr addObject:model];
        
    }];

高级用法: Map

    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"source.plist" ofType:nil];
    NSArray *dicArr = [NSArray arrayWithContentsOfFile:filePath];
    

    NSArray *modelArray = [[dicArr.rac_sequence map:^id(NSDictionary *value) {
     
        SourceModel *model = [[SourceModel alloc]init];
        model.name = x[@"name"];
        model.age = x[@"age"];
       
        return model;
    }] array];

5.ReactiveCocoa开发中常见用法

5.1 代替代理

  • RACSubject

  • rac_signalForSelector: 监听某个方法被调用了转化为信号, 就可以订阅了

    [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] 
        subscribeNext:^(id x) {
        
    }];


5.2 代替KVO

1. rac_observeKeyPath

#import "NSObject+RACKVOWrapper.h"

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    [self.view rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
        
    }];
    
    
}

2. rac_valuesForKeyPath

此方法把监听变化转化为一个信号, 成为信号后,即可订阅

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    [[self.view rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
        
    }];
    
    
}

5.3 监听事件

监听按钮点击事件

    UIButton *btn = [[UIButton alloc]init];
    
    [[btn rac_signalForControlEvents:UIControlEventTouchUpInside]
        subscribeNext:^(id x) {
        
    }];

5.4 代替通知

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] 
        subscribeNext:^(id x) {
        
    }];

5.5 监听文本框

把文本框内容的变化,转化为一个信号,进行订阅.

    UITextField *field = [UITextField new];
    [field.rac_textSignal subscribeNext:^(id x) {
        
    }];

5.6 处理界面有多次请求时, 需要都获取到数据时才能展示界面

  • rac_liftSelector:withSignalsFromArray:

这个方法中,第二个参数传入信号数组, 对应的第一个参数的回调方法就需要几个参数与之对应.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    
    RACSignal *sin1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       
        
        [subscriber sendNext:@"发送一个数据"];
        
        return nil;
    }];
    
    RACSignal *sin2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        
        [subscriber sendNext:@"又发送一个数据"];
        
        return nil;
    }];
    
    // 此方法会等到其数组内的信号全部sendNext后,才会执行selector.
    [self rac_liftSelector:@selector(updateUIWithData1:data2:) withSignalsFromArray:@[sin1,sin2]];
}

- (void)updateUIWithData1:(NSString *)stringFirst data2:(NSString *)stringSecound{
    
    
     /**
     *  参数的数据是和方法数组中信号的顺序一致.
     */
    NSLog(@"sin1Send:%@  sin2Send:%@",stringFirst,stringSecound);

}

6.ReactiveCocoa常见的宏

6.1 RAC(<#TARGET, ...#>)

用来给某个对象的某个属性绑定信号, 只要产生信号内容, 就会把内容给属性赋值.


    UILabel *label = [UILabel new];
    UITextField *textField = [UITextField new];
    
    // 普通写法
    [textField.rac_textSignal subscribeNext:^(id x) {
       
        label.text = x;
        
    }];
    
    // RAC宏写法
    // 用来给某个对象的某个属性绑定信号, 只要产生信号内容, 就会把内容给属性赋值.
    RAC(label,text) = textField.rac_textSignal;

6.2 RACObserve(<#TARGET#>, <#KEYPATH#>)

  // 1, 普通监听属性的方法
    [self.view rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
    
        NSLog(@"%@",value);
    }];
    
    
    // 2,RACObserve
    [RACObserve(self.view, frame) subscribeNext:^(id x) {
       
        NSLog(@"%@", x);
    }];

6.3 RACTuplePack 和 RACTupleUnpack

RACTuple *tuple = RACTuplePack(@1,@2);

NSLog(@"%@", tuple[0]);

RACTupleUnpack(NSNumber *number1, NSNumber *number2) = tuple;

NSLog(@"%@  %@", number1, number2);

7. RACMulticastConnection

用于当一个信号, 被多次订阅时, 为了保证创建信号时, 避免多次调用创建信号中的block, 造成副作用, 可以使用这个类处理.

RACMulticastConnection 这个类是结合了 RACSignalRACSubject 两个类来使用.

每个订阅者都保存在 RACMulticastConnectionRACSubject 中.

RACSubject作为 RACSignalRACSubscriber 用来 sendNext .

RACSubject sendNext 会遍历其中的所有的 订阅者 来 sendNext


  • 可以查看RACMulticastConnectionconnect方法
    // 1,创建信号
    RACSignal *sin = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       
        NSLog(@"请求数据");
        
        [subscriber sendNext:@"发送数据"];
        
        return nil;
    }];
    
    // 2,制作中间连接层
    RACMulticastConnection *connection = [sin publish];
    
    // 3,通过连接层订阅消息.
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"订阅者1");
    }];
    
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"订阅者2");

    }];
    
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"订阅者3");

    }];
    
    // 4,开始连接
    [connection connect];


8. RACCommand

RAC中用于处理事件的类, 可以把事件如何处理, 事件中的数据如何传递, 包装到这个类中, 它可以很方便的监控事件的执行过程.

  • 使用场景: 监听按钮点击, 网络请求.
    RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal *(id input) {
       
        
        NSLog(@"%@",input);
        
        
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
           
            [subscriber sendNext:@1];
            
            // 发送完成后, 可以设置sendCompleted.
            // 就可以改变command.executing中的bool值.
            [subscriber sendCompleted];
            
            return nil;
        }];
    }];
    
    
    [command.executionSignals subscribeNext:^(RACSignal *x) {
       
        [x subscribeNext:^(id x) {
            
            NSLog(@"xxxx111:%@",x);

            
        }];
        
    }];
    
    [command.executionSignals.switchToLatest subscribeNext:^(id x) {
        
        
        NSLog(@"xxxx222:%@",x);

    }];
    
    
    
    [command.executing subscribeNext:^(id x) {
       
        if ([x boolValue] == YES) {
            
            // 在发送先后后
            NSLog(@"正在执行.");
        }else{
            NSLog(@"执行完成/没有执行");
        }
        
    }];
    
    [command execute:@100];

对应的打印信息

执行完成/没有执行
100
正在执行.
xxxx111:1
xxxx222:1
执行完成/没有执行

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容