前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >函数响应式编程及ReactiveObjC学习笔记 (二)

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

作者头像
周希
发布于 2019-10-15 03:46:10
发布于 2019-10-15 03:46:10
50600
代码可运行
举报
文章被收录于专栏:APP自动化测试APP自动化测试
运行总次数:0
代码可运行

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#import <Foundation/Foundation.h>

@interface Student : NSObject

@property (nonatomic, strong) NSString *age;

@end

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    Student *stu = [[Student alloc] init];
    
    // RAC KVO
    [RACObserve(stu, age) subscribeNext:^(id  _Nullable x) {
        
        NSLog(@"stu的age改变为: %@", x);
    }];
    
    stu.age = @"10";

运行看看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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及事件绑定到一起

大概类似这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[button addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];

- (void)btnAction {
    
    NSLog(@"点击了按钮");
}

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    [[button
      rac_signalForControlEvents:UIControlEventTouchUpInside]
      subscribeNext:^(__kindof UIControl * _Nullable x) {
          
          NSLog(@"%@", x);
      }];

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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更换背景图片或者标题就可以在这里处理了, 我们用改变颜色举例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    [[button
      rac_signalForControlEvents:UIControlEventTouchUpInside]
      subscribeNext:^(__kindof UIControl * _Nullable x) {
          
          x.backgroundColor = [UIColor redColor];
      }];

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
    
    [[tap
     rac_gestureSignal]
     subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
         
         NSLog(@"点击了屏幕");
         NSLog(@"x: %@", x);
     }];
    
    [self.view addGestureRecognizer:tap];

运行看看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的颜色

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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如何帮我们实现通知的

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiAction) name:@"noti" object:nil];

- (void)notiAction {
    
    NSLog(@"接到了通知");
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[[NSNotificationCenter defaultCenter] postNotificationName:@"noti" object:nil userInfo:nil];

RAC会怎么帮我们实现呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    [[[NSNotificationCenter defaultCenter]
     rac_addObserverForName:@"noti" object:nil]
     subscribeNext:^(NSNotification * _Nullable x) {
         
         NSLog(@"接到了通知");
     }];

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

这样接口就清晰了

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

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

先写一个常规的AlertView

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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如何做

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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打印看看

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2017-07-23 12:53:07.138 RAC[68380:13356332] <RACTuple: 0x6080000149f0> (
    "<UIAlertView: 0x7fc7dfc0c620; frame = (0 0; 0 0); layer = <CALayer: 0x6000002218a0>>",
    1
)

我们看看这个RACTuple

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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;

打印看看

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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];

结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的具体用法

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-07-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
玩转MongoDB: 索引,速度的引领
数据库索引与书籍的索引类似,有了索引就不需要翻整本书,数据库可以直接在索引中查找,在索引中找到条目后,就可以直接跳到目标文档的位置,这可以让查找的速度提高几个数量级。
MongoDB中文社区
2018/08/14
1.6K0
玩转MongoDB: 索引,速度的引领
最全 MongoDB 基础教程
MongoDB 创建数据库 - 格式:use DATABASE_NAME - use ruochen - db创建数据库需要插入一条数据才会在列表中显示 - db.ruochen.insert({'name': '若尘'}) - show dbs 删除数据库 格式:db.dropDatabase() - use ruochen - db.dropDatabase() - show dbs 创建集合 - 格式:db.createCollection(name, options)
ruochen
2021/02/17
11.5K0
最全 MongoDB 基础教程
MongoDB 学习笔记
1、文档 --> 对应关系数据库的行,也就是一条记录。它比关系数据库的行的功能要强大,更像是是某个具体的对象。文档以一种Map的形式展现出来,当然value可以是任意的类型,也可以继续是一个文档(递归的定义)
阳光岛主
2019/02/18
7200
MongoDB常用命令(2)
批量操作需要和选择器同时使用,第一个false表示不执行insertOrUpdate操作,第二个true表示执行批量
Tom弹架构
2022/01/04
1.1K0
MongoDB的使用
1、在概念上,MongoDB的文档与Javascript的对象相近,因而可以认为它类似于JSON。JSON(http://www.json.org)是一种简单的数据表示方式:其规范仅用一段文字就能描述清楚(其官网证明了这点),且仅包含六种数据类型。
GH
2020/04/09
3.7K0
python操作mongodb数据库
(6) $push: 和 $ pushAll 都是向数组属性添加元素。# 好像两者没啥区别
bear_fish
2018/09/20
1.8K0
零基础学习MongoDB(五)—— 文档CRUD操作
语法格式:db.COLLECTION_NAME.insertOne(document)
小丞同学
2021/08/16
1.3K0
玩转mongodb(一):初识mongodb
ongodb中有三元素:数据库,集合,文档,其中“集合”就是对应关系型数据库中的“表”,“文档”对应“行”。
壮壮熊
2022/08/18
1.2K0
玩转mongodb(一):初识mongodb
玩转mongoDB(六):索引,速度的引领(普通索引篇)
数据库索引与书籍的索引类似,有了索引就不需要翻整本书,数据库可以直接在索引中查找,在索引中找到条目后,就可以直接跳到目标文档的位置,这可以让查找的速度提高几个数量级。
壮壮熊
2022/08/18
6010
玩转mongoDB(六):索引,速度的引领(普通索引篇)
MongoDB 集合与文档的相关操作
$pop修饰符删除数组中的第一个或者最后一个元素,给$pop传递-1会删除第一个元素传递1会删除最后一个元素
Power
2025/03/02
730
MongoDB 的 入门操作
为什么80%的码农都做不了架构师?>>> 1. 展示一下有那些数据库 show dbs use test show collections # 展示一下当前数据库的所有集合 2. 插入一条数据
北漂的我
2019/05/29
3890
MongoDB数据插入、删除、更新、批量更新某个字段
查询出hospitalName是xx医院和openId以2开头的所有记录,并且更新my_booking表中的payType为1.
周小董
2019/03/25
26.9K0
MongoDB数据插入、删除、更新、批量更新某个字段
MongoDB基本用法
顾翔
2024/09/10
890
MongoDB基本用法
玩转mongodb(二):mongodb基础知识
常用基本数据类型:nullnull用于表示空值或者不存在的字段:{"data":null}布尔型布尔类型只有两个值,true和false:{"data":true}、{"data":false}字符串字符串类型的数据是由UTF-8字符组成:{"data":"pingan"}正则表达式查询时,使用正则表达式作为限定条件,语法和javascript的正则表达式一样:{"data":/pingan/i}对象id对象id是一个12字节(24字符)的ID,是文档的唯一标识。{"data":ObjectId()}数值s
壮壮熊
2022/08/18
7350
玩转mongodb(二):mongodb基础知识
Studio 3T下操作MongoDB的基本命令(转载)
神农大表哥 数据库 围观1082次已关闭评论 编辑日期:2018-10-31 字体:大 中 小
拓荒者
2019/08/29
1.4K0
一口(很长的)气掌握mongodb基本操作nosql介绍安装mongodb库操作集合操作文档操作数据类型查询进阶聚合索引用户权限管理
nosql,全称是 not only sql, 即“不仅于sql”,相较于关系型数据库,nosql更加灵活,无需去维护复杂的数据关系。数据是json格式,更加直观易读。
章鱼喵
2018/09/26
3.1K0
一口(很长的)气掌握mongodb基本操作nosql介绍安装mongodb库操作集合操作文档操作数据类型查询进阶聚合索引用户权限管理
MongoDB权威指南学习笔记(1)--基础知识与对文档的增删改查
使用.来分割不同命名空间的子集合,例如一个博客系统可能包含两个集合,分别时blog.posts和blog.authors。
earthchen
2020/09/24
5.6K0
Mongodb PHP封装API类,实现基本的插入/修改/查询/删除操作
/* ============ 辅助操作接口API =============== */
程序猿的栖息地
2022/04/29
2.8K0
mongodb高级应用
一、  高级查询 查询操作符 条件操作符:db.collection.find({“field”:{$gt/$lt/$gte/$lte/$eq/$ne:value}}); 匹配所有:db.collection.find({age:{$all:[6,8]}});//字段的数组中符合全部条件才行。 判断字段存在:db.colletion.find({field:{$exists:true}})//还可用于remove等。 Null值的处理:db.collection.find({field:{“$in”:nul
一夕如环
2018/04/03
1.3K0
MongoDB
一 简介 MongoDB是一款强大、灵活、且易于扩展的通用型数据库 1、易用性 MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。 不采用关系型主要是为了获得更好得扩展性。当然还有一些其他好处,与关系数据库相比,面向文档的数据库不再有“行“(row)的概念取而代之的是更为灵活的“文档”(document)模型。 通过在文档中嵌入文档和数组,面向文档的方法能够仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的看法一致。 另外,不再有预定义模
用户1214487
2018/01/24
3.7K0
MongoDB
相关推荐
玩转MongoDB: 索引,速度的引领
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档