zoukankan      html  css  js  c++  java
  • 函数响应式编程及ReactiveObjC学习笔记 (二)

    之前我们初步认识了RAC的设计思路跟实现方式, 现在我们再来看看如果使用它以及它能帮我们做什么

    One of the major advantages of RAC is that it provides a single, unified approach to dealing with asynchronous behaviors, including delegate methods, callback blocks, target-action mechanisms, notifications, and KVO.

    官方是这样说的, RAC为我们提供了简单便捷实现代理 / block回调 / 事件 / 通知 / KVO的方式

    我们先看RAC如何帮助我们快速实现KVO

    首先我们新建一个Student类, 给它一个age的属性

    #import <Foundation/Foundation.h>
    
    @interface Student : NSObject
    
    @property (nonatomic, strong) NSString *age;
    
    @end

    下面我们看一个简单的如何使用RAC来实现KVO

        Student *stu = [[Student alloc] init];
        
        // RAC KVO
        [RACObserve(stu, age) subscribeNext:^(id  _Nullable x) {
            
            NSLog(@"stu的age改变为: %@", x);
        }];
        
        stu.age = @"10";

    运行看看:

    2017-07-23 11:35:19.704 RAC[67362:13075201] stu的age改变为: (null)
    2017-07-23 11:35:19.704 RAC[67362:13075201] stu的age改变为: 10

    很方便对吧, 不用我们去add observe, 不用出来观察事件, 也不用我们去移除关注

    不过大家注意到了没, 这里添加关注后block立即执行了一次, 大家可以依据实际项目情况加个条件判断做处理.

    这里其实RAC还为我们提供了除了subscriber以外的操作,  后面再介绍给, 现在我们主要先来看RAC是怎么替我们做KVO的

    我们再看看RAC如何帮我们实现target-action

    我们创建一个项目, 在controller中添加一个button, 然后给button添加一个点击事件

    如果是常规写法的话, 在创建完button后创建一个点击响应方法, 然后通过addTarget把响应方法跟button及事件绑定到一起

    大概类似这样:

    [button addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];
    
    - (void)btnAction {
        
        NSLog(@"点击了按钮");
    }

    在上一篇我们提到过这样的劣势, 当代码比较多的时候结构容易乱, 维护的时候也不好查找方法

    我们看看RAC如何帮我们优雅的实现

    RAC为我们提供了rac_signalForControlEvents来处理UIControllerEvent, 我们试试看

        [[button
          rac_signalForControlEvents:UIControlEventTouchUpInside]
          subscribeNext:^(__kindof UIControl * _Nullable x) {
              
              NSLog(@"%@", x);
          }];

    因为不知道这里的x是什么, 我们直接打印看看结果

    2017-07-23 12:05:59.654 RAC[67611:13189769] <UIButton: 0x7f95e0d069f0; frame = (157 350.5; 100 35); opaque = NO; layer = <CALayer: 0x6080000269a0>>

    当我们点击按钮打印了上面这些,  是我们创建的button对象

    那么加入需要点击的时候给button更换背景图片或者标题就可以在这里处理了, 我们用改变颜色举例

        [[button
          rac_signalForControlEvents:UIControlEventTouchUpInside]
          subscribeNext:^(__kindof UIControl * _Nullable x) {
              
              x.backgroundColor = [UIColor redColor];
          }];

    运行后, 就可以看到如果点击按钮背景就会变成红色, 如果有点击事件也可以放在这里

    但如果点击后要处理的逻辑比较多, 代码超过三行建议大家单独写一个方法供调用, 以免破坏代码的结构

    RAC这样的使用方式, 让我的代码逻辑更加清晰紧凑了, 我们再看一个添加手势的例子

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
        
        [[tap
         rac_gestureSignal]
         subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
             
             NSLog(@"点击了屏幕");
             NSLog(@"x: %@", x);
         }];
        
        [self.view addGestureRecognizer:tap];

    运行看看:

    2017-07-23 12:15:59.246 RAC[67766:13231274] 点击了屏幕
    2017-07-23 12:15:59.247 RAC[67766:13231274] x: <UITapGestureRecognizer: 0x6000001a5160; state = Ended; view = <UIView 0x7fb932d03780>; target= <(action=sendNext:, target=<RACPassthroughSubscriber 0x60800003a920>)>>

    这里x是一个手势, 我们可以直接拿来使用, 比如我们改变下添加手势这个view的颜色

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
        
        [[tap
         rac_gestureSignal]
         subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
             
             NSLog(@"点击了屏幕");
             NSLog(@"x: %@", x);
             x.view.backgroundColor = [UIColor redColor];
         }];
        
        [self.view addGestureRecognizer:tap];

    这样手势的初始化, 方法等等都在一起, 让代码一目了然

    接下来我们看看RAC如何帮我们实现通知的

    我们常规的通知应该是这样, 在要接收通知的地方添加关注通知并写上通知事件

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiAction) name:@"noti" object:nil];
    
    - (void)notiAction {
        
        NSLog(@"接到了通知");
    }

    然后在对应的地方发送通知

    [[NSNotificationCenter defaultCenter] postNotificationName:@"noti" object:nil userInfo:nil];

    RAC会怎么帮我们实现呢?

        [[[NSNotificationCenter defaultCenter]
         rac_addObserverForName:@"noti" object:nil]
         subscribeNext:^(NSNotification * _Nullable x) {
             
             NSLog(@"接到了通知");
         }];

    发送通知iOS已经很简单了, RAC没有做重复工作但帮我们把添加关注通知的方法改进了, 可以让事件和通知关注在一起

    这样接口就清晰了

    那么RAC如果帮我们实现代理呢?

    我用UIAlertView给大家举个例子, 虽然苹果已经不推荐用这个 不过我们拿来当例子用用看

    先写一个常规的AlertView

    #import "ViewController.h"
    #import <ReactiveObjC.h>
    
    @interface ViewController ()<UIAlertViewDelegate>
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
        
        [alertView show];
        
    }
    
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
        
        if (buttonIndex == 0) {
            
            NSLog(@"点击了Cancel按钮");
        } else {
            
            NSLog(@"点击了Ok按钮");
        }
    }
    
    @end

    初始化alertView, 实现代理方法 这是我们常规的用法

    那么我们再看看RAC如何做

    #import "ViewController.h"
    #import <ReactiveObjC.h>
    
    @interface ViewController ()<UIAlertViewDelegate>
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
        
        [[self
         rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]
         subscribeNext:^(RACTuple * _Nullable x) {
             
             NSLog(@"%@", x);
         }];
        
        [alertView show];
        
    }
    
    @end

    RAC为我们提供了一个rac_signalForSelector: fromProtoc方法帮我们实现代理

    我们把x打印看看

    2017-07-23 12:53:07.138 RAC[68380:13356332] <RACTuple: 0x6080000149f0> (
        "<UIAlertView: 0x7fc7dfc0c620; frame = (0 0; 0 0); layer = <CALayer: 0x6000002218a0>>",
        1
    )

    我们看看这个RACTuple

    @interface RACTuple : NSObject <NSCoding, NSCopying, NSFastEnumeration>
    
    @property (nonatomic, readonly) NSUInteger count;
    
    /// These properties all return the object at that index or nil if the number of 
    /// objects is less than the index.
    @property (nonatomic, readonly, nullable) id first;
    @property (nonatomic, readonly, nullable) id second;
    @property (nonatomic, readonly, nullable) id third;
    @property (nonatomic, readonly, nullable) id fourth;
    @property (nonatomic, readonly, nullable) id fifth;
    @property (nonatomic, readonly, nullable) id last;

    打印看看

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
        
        [[self
         rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]
         subscribeNext:^(RACTuple * _Nullable x) {
             
             NSLog(@"%@", x);
             NSLog(@"first: %@", x.first);
             NSLog(@"second: %@", x.second);
             NSLog(@"third: %@", x.third);
             NSLog(@"fourth: %@", x.fourth);
             NSLog(@"fifth: %@", x.fifth);
             NSLog(@"last: %@", x.last);
         }];
        
        [alertView show];

    结果为:

    2017-07-23 16:29:26.089 RAC[68525:13409884] first: <UIAlertView: 0x7f814e604420; frame = (0 0; 0 0); layer = <CALayer: 0x60800003a3e0>>
    2017-07-23 16:29:26.090 RAC[68525:13409884] second: 1
    2017-07-23 16:29:26.090 RAC[68525:13409884] third: (null)
    2017-07-23 16:29:26.090 RAC[68525:13409884] fourth: (null)
    2017-07-23 16:29:26.091 RAC[68525:13409884] fifth: (null)
    2017-07-23 16:29:26.091 RAC[68525:13409884] last: 1

    第一个是alert本身, 第二个是index, 然后可以按我们的需要做处理了

    另外要注意的是用RAC写代理是有局限的,它只能实现返回值为void的代理方法

    先到这里, 现在我们知道我们能用RAC做什么了

    下次我们继续看RAC的具体用法

  • 相关阅读:
    借着面试留点东西
    buffer cache(zz)
    vmstat 命令
    部分mysql知识
    RandomAccessFile和FileInputOutPutStream
    lock condition
    tornado开发学习之2.输入输出,数据库操作,内置模板,综合示例
    tornado开发学习之1.HelloWorld和它加强版版本
    ASP.NET MVC框架
    Highcharts中UTC使用的注意点
  • 原文地址:https://www.cnblogs.com/zhouxihi/p/7225341.html
Copyright © 2011-2022 走看看