函数响应式编程及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的具体用法

时间: 2024-10-26 05:24:42

函数响应式编程及ReactiveObjC学习笔记 (二)的相关文章

函数响应式编程及ReactiveObjC学习笔记 (-)

最近无意间看到一个视频讲的ReactiveObjC, 觉得挺好用的 但听完后只是了解个大概. 在网上找了些文章, 有的写的比较易懂但看完还是没觉得自己能比较好的使用RAC, 有的甚至让我看不下去 这两天刚好公司项目交付闲下来, 想自己去啃下官方文档 ReactiveCocoa是一个基于函数响应式编程的OC框架. 那么什么是函数式响应式编程呢?概念我就不讲了 因为我讲的也不一定准确, 大家可以去baidu看看大神们的解释 下面我大概演示下响应式编程的样子 Masonry是比较常见的一个响应式框架,

高大上函数响应式编程框架ReactiveCocoa学习笔记1 简介

原创文章,转载请声明出处哈. ReactiveCocoa函数响应式编程 一.简介 ReactiveCocoa(其简称为RAC)是函数响应式编程框架.RAC具有函数式编程和响应式编程的特性.它主要吸取了.Net的 Reactive Extensions的设计和实现. 函数式编程 (Functional Programming) 函数式编程也可以写N篇,它是完全不同于OO的编程模式,这里主要讲一下这个框架使用到的函数式思想. 1) 高阶函数:在函数式编程中,把函数当参数来回传递,而这个,说成术语,我

什么是函数响应式编程(Java&amp;Android版本)

什么是函数响应式编程(Java&Android版本) 原文链接:http://www.bignerdranch.com/blog/what-is-functional-reactive-programming/ 函数响应式编程(FRP)为解决现代编程问题提供了全新的视角.一旦理解它,可以极大地简化你的项目,特别是处理嵌套回调的异步事件,复杂的列表过滤和变换,或者时间相关问题. 我将尽量跳过对函数响应式编程学院式的解释(网络上已经有很多),并重点从实用的角度帮你理解什么是函数响应式编程,以及工作中

函数响应式编程(FRP)思想

序 ReactiveCocoa是IOS广为使用的技术框架,而ReactiveCocoa的核心思想就FRP.FRP不同于JAVA的object-oriented和AOP,FRP能让你的代码像数学一样简洁,业务像流水一样清晰流畅. 函数响应式编程 响应式编程思想为体,函数式编程思想为用. 响应式编程 例如,在命令式编程环境中, a:=b+c表示将表达式的结果赋给 a,而之后改变 b 或 c的值不会影响 a.但在响应式编程中,a的值会随着 b或 c的更新而更新. 在响应式编程当中,a:=b+c声明的是

响应式编程框架ReactiveCocoa学习——框架概览

这篇博客将会继续翻译RAC的官方文档Framework Overview. 主要是对RAC这和框架进行概览的介绍和学习.同时也可以参考我前面的两篇翻译<响应式编程框架ReactiveCocoa学习--基本操作符><响应式编程框架ReactiveCocoa介绍与入门>.其中ReactiveCocoa的Github官方地址为 https://github.com/ReactiveCocoa/ReactiveCocoa . 这篇文档包括了RAC中的对不同组件的高层描述,并解释如何进行结合

ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一!

ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一! 简介 项目主页: ReactiveCocoa 实例下载: https://github.com/ios122/ios122 简评: 最受欢迎,最有价值的iOS响应式编程库,没有之一!iOS MVVM模式的完美搭档,更多关于MVVM与ReactiveCocoa的讨论,参考这篇文章: [长篇高能]ReactiveCocoa 和 MVVM 入门 注意: ReactiveCocoa 最新3.0版本,使用Swift重写,

函数响应式编程(FRP)思想-Callback风格

序 ReactiveCocoa是IOS广为使用的技术框架,而ReactiveCocoa的核心思想就FRP.FRP不同于JAVA的object-oriented和AOP,FRP能让你的代码像数学一样简洁,业务像流水一样清晰流畅. 函数响应式编程 响应式编程思想为体,函数式编程思想为用.  响应式编程 例如,在命令式编程环境中, a:=b+c表示将表达式的结果赋给 a,而之后改变 b 或 c的值不会影响 a.但在响应式编程中,a的值会随着 b或 c的更新而更新. 在响应式编程当中,a:=b+c声明的

RxJS入门之函数响应式编程

一.函数式编程 1.声明式(Declarativ) 和声明式相对应的编程?式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的?种编程?式. //命令式编程: function double(arr) { const results = [] for (let i = 0; i < arr.length; i++){ results.push(arr[i] * 2) } return results } function addOne(arr){ const r

RxJava响应式编程之初级了解

据说现在流行的开发模式是 Retrofit+RxJava+MVP+ButterKnife 如果想要简单学习ButterKnife.MVP模式,可以参考我以前的例子 使用butterknife注解框架 Android-MVP设计模式高级(三) 今天我就简单来学习下RxJava的相关知识 以前我也只是听说过RxJava,RxJava这个到底是什么东西呢? 呵呵,它其实是一个库,所以我们使用里面的方法,得需要下载库,所以我们需要在AS中进行配置 1.RxJava 地址以及添加 github地址: ht