ReactiveCocoa

2016-02-13  本文已影响715人  rxdxxxx

RedRain的简书:http://www.jianshu.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响应式编程思想

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

3.5函数式编程思想

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

本质:

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

特点:

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

代表:

ReactiveCocoa

4.ReactiveCocoa

4.1 RACSignal

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

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的解释来理解与其他类的区别

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

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 代替代理

    [[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 处理界面有多次请求时, 需要都获取到数据时才能展示界面

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

- (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


    // 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
执行完成/没有执行

上一篇 下一篇

猜你喜欢

热点阅读