Notes and thoughts from Tony

ReactiveCocoa用法和宏

Comments

常见用法

之前提到了RAC可以代替代理、KVO等。现在来看看具体用法。

代替代理:

  • rac_signalForSelector:用于替代代理。

  • 原理:判断一个方法有没有调用,如果调用了就会自动发送一个信号。

  • 需求:自定义CustomView,监听自定义view中按钮点击

  • 之前都是需要通过代理监听,给自定义view添加一个代理属性,点击按钮的时候,通知代理做事情。

  • rac_signalForSelector:把调用某个对象的方法的信息转换成信号,就要调用这个方法,就会发送信号。

  • 这里表示只要CustomView调用btnClick,就会发出信号,订阅就好了。

代码:

//CustomView
- (IBAction)buttonDidClick:(UIButton *)sender {
    NSLog(@"buttonDidClick");
}

//DelegateViewController
[[self.customView rac_signalForSelector:@selector(buttonDidClick:)] subscribeNext:^(id x) {
    NSLog(@"控制器知道:点击了按钮");
}];
2016-03-20 22:43:17.731 RACDemo[46034:5333662] buttonDidClick
2016-03-20 22:43:17.737 RACDemo[46034:5333662] 控制器知道:点击了按钮

代替KVO :

  • rac_valuesAndChangesForKeyPath:用于监听某个对象的属性改变。

  • 方法调用者:就是被监听的对象。

  • KeyPath:监听的属性。

  • 把监听redV的center属性改变转换成信号,只要值改变就会发送信号。

  • observer:可以传入nil。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor randomColor];
    
    Cat *cat = [Cat new];
    self.cat = cat;
    
    [[self.cat rac_valuesAndChangesForKeyPath:@"age" options:NSKeyValueObservingOptionNew observer:nil]  subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.cat.age += 1;
}
2016-03-21 10:18:26.130 RACDemo[46460:5399402] <RACTuple: 0x17400e460> (
    5,
        {
        kind = 1;
        new = 5;
    }
)

监听事件:

  • rac_signalForControlEvents:用于监听某个事件。

  • 把按钮点击事件转换为信号,点击按钮,就会发送信号。

[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {

        NSLog(@"按钮被点击了");
    }];
2016-03-21 10:34:02.781 RACDemo[46512:5404121] 按钮被点击了

代替通知:

  • rac_addObserverForName:用于监听某个通知。

  • 只要发出这个通知,又会转换成一个信号。

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
   NSLog(@"弹出键盘");
}];
2016-03-21 10:42:13.226 RACDemo[46545:5406463] 弹出键盘

监听文本框文字改变:

  • rac_textSignal:只要文本框发出改变就会发出这个信号。

  • 获取文本框文字改变的信号。

[self.textfield.rac_textSignal subscribeNext:^(id x) {
   NSLog(@"%@", x);
}];
2016-03-21 10:45:44.464 RACDemo[46557:5407311] r
2016-03-21 10:45:44.743 RACDemo[46557:5407311] rr
2016-03-21 10:45:44.960 RACDemo[46557:5407311] rrh

liftSelector

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

  • rac_liftSelector:withSignalsFromArray:Signals:当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法。

  • 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。

  • 不需要主动订阅signalA和signalB,方法内部会自动订阅。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor randomColor];
    
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        double delayInSeconds = 2.0;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [subscriber sendNext:@"A"];
        });
        return nil;
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"B"];
        [subscriber sendNext:@"Another B"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    [self rac_liftSelector:@selector(doA:withB:) withSignals:signalA, signalB, nil];
}

- (void)doA:(NSString *)A withB:(NSString *)B {
    NSLog(@"A:%@ and B:%@", A, B);
}
2016-03-21 11:11:17.527 RACDemo[46668:5415565] A:A and B:Another B

RAC常见宏

RAC(TARGET, [KEYPATH, [NIL_VALUE]])

  • 用于给某个对象的某个属性绑定。把一个对象的某个属性绑定一个信号,只要发出信号,就会把信号的内容给对象的属性赋值。

  • 实现了label的内容跟随textField内容的改变而改变。

RAC(self.label, text) = self.textField.rac_textSignal;

RACObserve(self, name)

  • 用于给某个对象的某个属性绑定。

  • 快速的监听某个对象的某个属性改变。

  • 返回的是一个信号,对象的某个属性改变的信号。

[RACObserve(self.view, center) subscribeNext:^(id x) {
   NSLog(@"%@", NSStringFromCGRect(self.textField.frame));
}];
2016-03-21 11:25:47.710 RACDemo[46722:5419085] { {198, 156}, {205, 30} }

RACTuplePack和RACTupleUnpack

  • RACTuplePack:把数据包装成RACTuple(元组类)。把包装的类型放在宏的参数里面,就会自动包装。

  • RACTupleUnpack:把RACTuple(元组类)解包成对应的数据。等号的右边表示解析哪个元组。宏的参数:表示解析成什么类型。

RACTuple *tuple = RACTuplePack(@1,@3);
NSLog(@"%@", tuple);
    
RACTupleUnpack(NSNumber *num1,NSNumber *num2) = tuple;
NSLog(@"%@ %@", num1, num2);
2016-03-21 11:28:32.712 RACDemo[46736:5420042] <RACTuple: 0x17400c4d0> (
    1,
    3
)
2016-03-21 11:28:32.713 RACDemo[46736:5420042] 1 3

代码:

文章中的代码都可以从我的GitHub RACDemo找到。