捣腾ReactiveCocoa

本文详细介绍ReactiveCocoa在iOS开发中的应用,包括环境配置、基本操作如监听UITextField、按钮点击,以及高级技巧如取消订阅、信号创建、链接类使用。文章还探讨了RACCommand宏的使用,如何代替代理、KVO、事件监听和通知,以及解决循环引用问题。
摘要由CSDN通过智能技术生成

起因:ReactiveCocoa一直没能找时间出来学习,也没有实际使用过,今天来图书馆一游,专门静下心解决这个课题.

一、环境配置

新建一个工程,这里遇到一个问题,ReactiveCocoa只能由Pod导入,又捣腾了CocoaPod的安装,好久没搞这个又花了点时间,把过程记录下来.

新工程CocoaPods的配置(只限已经安装了CocoaPods基础上)

1.命令行cd到工程目录

2.vim Podfile,创建Podfile,并编辑

target 'TestRAC' do

    pod 'ReactiveCocoa', '~> 4.1.0'

end

3.命令行输入:pod update 更新本地pod库(这个过程比较漫长,我这边下载到本地的库有600M+,时间大概10分钟,可以查看/Users/mac/.cocoapods/ 文件夹大小确定是否在下载中..),最终命令行显示更新完库后.我们进入下一步.

4.命令行输入:pod update 创建工程的pod库和xcworkspace

等后片刻工程里已经生成xcworkspace,和已经安装好了ReactiveCocoa

运行后发现工程报错,报错信息如下:

The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targets which use Swift. Supported values are: 3.0, 4.0, 4.2. This setting can be set in the build settings editor.

问题原因:xcode10已经抛弃了swift2.0.编译项已经无法选择2.0.

解决:用xcode9打开工程,运行成功!

二、开始学习ReactiveCocoa

简单入门:

1、监听UITextField

    //监听UITextField的输入,

    //x为输入的全部文字

    [[self.textF rac_textSignal]subscribeNext:^(NSString * _Nullable x) {

        NSLog(@"%@",x);

    }];

2、监听按钮点击

    //监听按钮点击事件

    //x为UIButton

    RACDisposable *disposable = [[self.button rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {

            NSLog(@"%@",x);

    }];

3、把通知封装成block

    //监听通知

    //x为NSNotification,object为UIApplication

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidBecomeActiveNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {

        NSLog(@"%@",x);

    }];

4、自定义信号

    //自定义信号
    //信号新的订阅者会执行block里的所有方法
    RACSignal *customSingal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"信号创建中");
        [subscriber sendNext:@"lalala"];
        NSLog(@"信号发送完毕");
        return nil;
    }];
    [customSingal subscribeNext:^(id  _Nullable x) {
        NSLog(@"订阅者1 收到信号%@",x);
    }];
    
    [customSingal subscribeNext:^(id  _Nullable x) {
        NSLog(@"订阅者2 收到信号%@",x);
    }];

信号的订阅者会执行block里的所有方法,那么我们只想执行信号发送这部分怎么办呢?

这时候有一个新类叫链接类:RACMulticastConnection,使用方法如下:

    //自定义信号
    //信号新的订阅者会执行block里的所有方法
    RACSignal *customSingal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"信号创建中");
        [subscriber sendNext:@"lalala"];
        NSLog(@"信号发送完毕");
        return nil;
    }];

    //把信号转为链接类,链接类只执行信号创建时block中RACSubject产生的信号
    RACMulticastConnection *connection = [customSingal publish];
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"链接器1 接收到信号");
        NSLog(@"%@",x);
    }];
    
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"链接器2 接收到信号");
        NSLog(@"%@",x);
    }];
    //链接信号
    [connection connect];

5.取消订阅信号

这里我们以取消按钮点击的例子为例:

    //监听按钮点击事件
    //x为UIButton
    RACDisposable *disposable = [[self.button rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
            NSLog(@"%@",x);
    }];
    
    //当想取消订阅的时候调用创建信号调用 dispose 就可以取消
    //3秒后取消订阅
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //
        [disposable dispose];
    });

注意:block中的循环引用问题

RAC使用@weakify(self);和@strongify(self);来避免block循环引用

@weakify(self);

[[self.textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {

    @strongify(self);

    self.textField.text = @"Hello";

}];

高级使用:

1、RACCommand常用的宏

1.1 RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定。

//RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定。
-(void)testMacroRAC{
    RAC(self.label,text) = self.textF.rac_textSignal;
    RAC(self.label2,text) = self.textF.rac_textSignal;
    [self.textF.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
         NSLog(@"%@",x);
     }];
}

效果如下:

1.2 //RACObserve(self, name):监听某个对象的某个属性,返回的是信号。

//RACObserve(self, name):监听某个对象的某个属性,返回的是信号。
-(void)testMacroRACObserve{
    RAC(self.label,text) = self.textF.rac_textSignal;
    [RACObserve(self.label, text)subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    RAC(self.label2,text) = RACObserve(self.label, text);
}

 

RACCommand 这个用的不多,暂时不试验了

 

补充常用用法

  • 代替代理:

  • rac_signalForSelector:用于替代代理。

  • RACSubject:也用于代理.

 

  // 需求:自定义BlueView,监听BlueView中按钮点击

    // 之前都是需要通过代理监听,点击按钮的时候,通知代理做事情

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

    // 这里表示只要blueView调用clickBlueViewButton,就会发出信号,订阅就好了。

   [[self.blueView rac_signalForSelector:@selector(clickBlueViewButton)] subscribeNext:^(id x) {

         NSLog(@"点击了蓝色视图上的按扭");

     }];

 

  • 代替KVO :

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

 

   [[self.blueView rac_valuesAndChangesForKeyPath:@"frame" options:NSKeyValueObservingOptionNewobserver:nil] subscribeNext:^(id x) {

        NSLog(@"%@",x);

    }];

 

  • 监听事件:

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

 

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

//监听事件

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

 

         NSLog(@"点击了按扭");

     }];

 

  • 代替通知:

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

 

// 把监听到的通知转换信号

   [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillChangeFrameNotificationobject:nil] subscribeNext:^(id x) {

        NSLog(@"键盘frame发生改变%@",x);

    }];

 

  • 监听文本框文字改变:

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

 

// 5.监听文本框的文字改变

   [self.textfield.rac_textSignal subscribeNext:^(id x) {

 

            NSLog(@"%@",x);

        }];

关于信号接收者要dealloc的时候取消订阅

错误的方式如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    //任务继续执行
    //SecondVC dealloc
    [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * _Nullable x) {
        [SecondVC print];
    }];
}

+(void)print{
    NSLog(@"一秒执行一次");
}
-(void)dealloc{
    NSLog(@"%@ dealloc",NSStringFromClass(self.class));
}

运行如下:

这种订阅方式在订阅者dealloc的时候并不会停止,订阅者的任务依然在执行

正确的方式如下:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor yellowColor];

//    takeUntil 一直订阅直到收到后面的信号才停止订阅
    [[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]takeUntil:self.rac_willDeallocSignal]subscribeNext:^(NSDate * _Nullable x) {
        [SecondVC print];
    }];
}

+(void)print{
    NSLog(@"一秒执行一次");
}

-(void)dealloc{
    NSLog(@"%@ dealloc",NSStringFromClass(self.class));
}

运行如下:

我们看到在订阅者dealloc后,任务也停止了

takeUntil 一直订阅直到收到后面的信号才停止订阅,一般这样用,不然任务会一直执行


 

以上部分转载.

 

ReactiveCocoa学习参考:

简单入门:http://www.cocoachina.com/ios/20171227/21667.html

深入研究:

https://www.cnblogs.com/fengmin/p/5662270.html

https://www.jianshu.com/p/3db561083fef

https://blog.csdn.net/z929118967/article/details/75547326

(组合,聚合,同步等高级用法):

https://www.cnblogs.com/czc-wjm/p/5655282.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值