ReactiveCocoa学习笔记-RAC的基础与简单使用

什么是Functional Reactive Programming?
Functional Reactive Programming(以下简称FRP)是一种响应变化的编程范式

a = 2
b = 2
c = a + b  // c is 4
b = 3  // now what is the value of c?

没错,如果使用FRP的话c的值会随着b的值变化而改变,这叫做「响应式编程」。



ReactiveCocoa(以下简称RAC)是在iOS开发中对FRP的实现FRP的核心是信号,
在RAC中信号使用RACSignal表示

可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。可以在水龙头上加一个过滤嘴(filter),不符合的不让通过,也可以加一个改动装置,把球改变成符合自己的需求(map)。也可以把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。





下面就来一些简单的代码示例:
想获取nameTextFielttext实时赋值给某一模型username变量:

RAC(self, username) = self.nameTextFielt.rac_textSignal;

这是把nameTextFielt的信号绑定username这个属性上来,
和这里是一样的:

[self.nameTextFielt.rac_textSignal subscribeNext:^(NSString* x) {
        self.username = x;
    }];

nameTextFielt的信号添加一个订阅者,这样每当text的值变化的时候就会有信号产生,我们可以在block里拿到这个text的变化的值来做操作。



如果不是每个信号都会处理,比如我们只想知道当输入了6个字符之后的字符串,可以这样把信号过滤(filter)

[[self.nameTextFielt.rac_textSignal filter:^BOOL(NSString* value) {
        return value.length > 6;
    }] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];




我们还可以映射(map)信号,比如想把用户输入的字符串转换为NSNumber类型:

[[self.nameTextFielt.rac_textSignal map:^id(NSString* value) {
        return @(value.integerValue);
    }]subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];




当然,信号还能被合并(combine),在用户登录的时候如果希望当用户名和密码输入长度大于6之后登录按钮才能点击,反正则不能:

RACSignal *ableSignal = [RACSignal combineLatest:@[self.nameTextFielt.rac_textSignal, self.passwordTextFielt.rac_textSignal] reduce:^id(NSString *name,  NSString *pswd){
        return @( name.length>6 && pswd.length>6 );
    }];
RAC(self.loginButton, enabled) = ableSignal;




但是我们通常并不这么干,而是去用RACSignal去实例一个RACCommand对象,并且为我们的登录按钮绑定该命令:

RACCommand *loginCommand = [[RACCommand alloc]initWithEnabled:ableSignal signalBlock:^RACSignal *(id input) {
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            //在这里做登录请求
            BOOL success = YES;
            if (success) { // 登录成功
                [subscriber sendNext:@(success)];
                [subscriber sendCompleted];
            }else{ // 登录失败
                [subscriber sendError:[NSError new]];
                [subscriber sendCompleted];
            }
            return nil;
        }];
    }];

self.loginButton.rac_command = loginCommand;

这么做还有个好处,当subscriber不进行sendCompleted,即网络请求未返回时,按钮处于不可点击状态,可以防止重复提交



但是,如果我们想拿到网络请求返回的结果怎么办?
在上个代码中,如果网络请求成功的话,可以把返回结果返回:

[subscriber sendNext:result];
[[self.loginButton.rac_command execute:nil]subscribeNext:^(id x) {
        // x 即为网络返回的数据
    }];

转载于:https://www.cnblogs.com/xiubin/p/5039532.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值