写点什么

ReactiveCocoa - iOS 开发的新框架

  • 2014-02-11
  • 本文字数:3322 字

    阅读完需:约 11 分钟

ReactiveCocoa (其简称为 RAC)是由 Github 开源的一个应用于 iOS 和 OS X 开发的新框架。RAC 具有函数式编程和响应式编程的特性。它主要吸取了.Net 的 Reactive Extensions 的设计和实现。本文将详细介绍该框架试图解决什么问题,以及其用法与特点。

ReactiveCocoa 试图解决什么问题

经过一段时间的研究,我认为 ReactiveCocoa 试图解决以下 3 个问题:

  1. 传统 iOS 开发过程中,状态以及状态之间依赖过多的问题
  2. 传统 MVC 架构的问题:Controller 比较复杂,可测试性差
  3. 提供统一的消息传递机制

传统 iOS 开发过程中,状态以及状态之间依赖过多的问题

我们在开发 iOS 应用时,一个界面元素的状态很可能受多个其它界面元素或后台状态的影响。

例如,在用户帐户的登录界面,通常会有 2 个输入框(分别输入帐号和密码)和一个登录按钮。如果我们要加入一个限制条件:当用户输入完帐号和密码,并且登录的网络请求还未发出时,确定按钮才可以点击。通常情况下,我们需要监听这两个输入框的状态变化以及登录的网络请求状态,然后修改另一个控件的enabled状态。

传统的写法如下(该示例代码修改自 ReactiveCocoa 官网 ) :

复制代码
static void *ObservationContext = &ObservationContext;
(void)viewDidLoad {
[super viewDidLoad];
[LoginManager.sharedManager addObserver:self
forKeyPath:@"loggingIn"
options:NSKeyValueObservingOptionInitial
context:&ObservationContext];
[self.usernameTextField addTarget:self action:@selector(updateLogInButton)
forControlEvents:UIControlEventEditingChanged];
[self.passwordTextField addTarget:self action:@selector(updateLogInButton)
forControlEvents:UIControlEventEditingChanged];
}
- (void)updateLogInButton {
BOOL textFieldsNonEmpty = self.usernameTextField.text.length > 0
&& self.passwordTextField.text.length > 0;
BOOL readyToLogIn = !LoginManager.sharedManager.isLoggingIn && !self.loggedIn;
self.logInButton.enabled = textFieldsNonEmpty && readyToLogIn;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (context == ObservationContext) {
[self updateLogInButton];
} else {
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}

RAC 通过引入信号(Signal)的概念,来代替传统 iOS 开发中对于控件状态变化检查的代理(delegate)模式或 target-action 模式。因为 RAC 的信号是可以组合(combine)的,所以可以轻松地构造出另一个新的信号出来,然后将按钮的enabled状态与新的信号绑定。如下所示:

复制代码
RAC(self.logInButton, enabled) = [RACSignal
combineLatest:@[
self.usernameTextField.rac_textSignal,
self.passwordTextField.rac_textSignal,
RACObserve(LoginManager.sharedManager, loggingIn),
RACObserve(self, loggedIn)
] reduce:^(NSString *username, NSString *password, NSNumber *
loggingIn, NSNumber *loggedIn) {
return @(username.length > 0 && password.length > 0 && !
loggingIn.boolValue && !loggedIn.boolValue);
}];

可以看到,在引入 RAC 之后,以前散落在action-target或 KVO 的回调函数中的判断逻辑被统一到了一起,从而使得登录按钮的enabled状态被更加清晰地表达了出来。

除了组合(combine)之外,RAC 的信号还支持链式(chaining)和过滤(filter),以方便将信号进行进一步处理。

试图解决 MVC 框架的问题

对于传统的 Model-View-Controller 的框架,Controller 很容易变得比较庞大和复杂。由于 Controller 承担了 Model 和 View 之间的桥梁作用,所以 Controller 常常与对应的 View 和 Model 的耦合度非常高,这同时也造成对其做单元测试非常不容易,对 iOS 工程的单元测试大多都只在一些工具类或与界面无关的逻辑类中进行。

RAC 的信号机制很容易将某一个 Model 变量的变化与界面关联,所以非常容易应用 Model-View-ViewModel 框架。通过引入 ViewModel 层,然后用 RAC 将 ViewModel 与 View 关联,View 层的变化可以直接响应 ViewModel 层的变化,这使得 Controller 变得更加简单,由于 View 不再与 Model 绑定,也增加了 View 的可重用性。

因为引入了 ViewModel 层,所以单元测试可以在 ViewModel 层进行,iOS 工程的可测试性也大大增强了。InfoQ 也曾撰文介绍过 MVVM:《MVVM 启示录》

统一消息传递机制

iOS 开发中有着各种消息传递机制,包括 KVO、Notification、delegation、block 以及 target-action 方式。各种消息传递机制使得开发者在做具体选择时感到困惑,例如在 objc.io 上就有专门撰文破船的翻译 ),介绍各种消息传递机制之间的差异性。

RAC 将传统的 UI 控件事件进行了封装,使得以上各种消息传递机制都可以用 RAC 来完成。示例代码如下:

复制代码
// KVO
[RACObserve(self, username) subscribeNext:^(id x) {
NSLog(@" 成员变量 username 被修改成了:%@", x);
}];
// target-action
self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:
^RACSignal *(id input) {
NSLog(@" 按钮被点击 ");
return [RACSignal empty];
}];
// Notification
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(keyboardDidChangeFrameNotificationHandler:)
name:UIKeyboardDidChangeFrameNotification object:nil];

RAC 的RACSignal 类也提供了createSignal方法来让用户创建自定义的信号,如下代码创建了一个下载指定网站内容的信号。

复制代码
(RACSignal *)urlResults {
return [RACSignal createSignal:^RACDisposable *(id<racsubscriber> subscriber) { NSError *error; NSString *result = [NSString stringWithContentsOfURL: [NSURL URLWithString:@"http://www.devtang.com"] encoding:NSUTF8StringEncoding error:&error]; NSLog(@"download"); if (!result) { [subscriber sendError:error]; } else { [subscriber sendNext:result]; [subscriber sendCompleted]; } return [RACDisposable disposableWithBlock:^{ NSLog(@"clean up"); }]; }]; }</racsubscriber>

如何使用 ReactiveCocoa

ReactiveCocoa 可以在 iOS 和 OS X 的应用开发中使用,对于 iOS 开发者,可以将 RAC 源码下载编译后,使用编译好的libReactiveCocoa-iOS.a文件。

开发者也可以用 CocoaPods 来设置目标工程对 ReactiveCocoa 的依赖,只需要编辑 Podfile 文件,增加如下内容即可:

复制代码
pod 'ReactiveCocoa', ‘2.0'

ReactiveCocoa 的特点

RAC 在应用中大量使用了 block,由于 Objective-C 语言的内存管理是基于引用计数 的,为了避免循环引用问题,在block 中如果要引用self,需要使用 @weakify(self)@strongify(self)来避免强引用。另外,在使用时应该注意 block 的嵌套层数,不恰当的滥用多层嵌套 block 可能给程序的可维护性带来灾难。

RAC 的编程方式和传统的 MVC 方式差异巨大,所以需要较长的学习时间。并且,业界内对于 RAC 并没有广泛应用,这造成可供参考的项目和教程比较欠缺。另外,RAC 项目本身也还在快速演进当中,1.x 版本和 2.x 版本 API 改动了许多,3.0 版本也正在快速开发中,对它的使用也需要考虑后期的升级维护问题。

作为一个 iOS 开发领域的新开源框架,ReactiveCocoa 带来了函数式编程和响应式编程的思想,值得大家关注并且学习。

作者简介:

唐巧,资深 iOS 开发者和 Blogger,曾开发有道云笔记、猿题库和粉笔网的 iOS 客户端。他维护着 iOS 开发博客 http://www.devtang.com/ 和微信 iOS 开发公众账号 iosDevTips。唐巧在 2014 年 QCon 北京将进行一场 iOS 开发进阶的培训,介绍如何基于 CoreText 自己实现一个排版引擎

2014-02-11 00:2540329
用户头像

发布了 65 篇内容, 共 56.3 次阅读, 收获喜欢 23 次。

关注

评论

发布
暂无评论
发现更多内容

规模化、可复制的大模型应用——企业知识管家

九章云极DataCanvas

一个 println 竟然比 volatile 还好使? | 京东云技术团队

京东科技开发者

volatile JIT 企业号9月PK榜 println

研究了代码质量后,开发效率提升10倍,bug减少20倍!!

SoFlu-JavaAI开发助手

交易日均千万订单的存储架构设计与实践 | 京东物流技术团队

京东科技开发者

架构设计 订单系统 存储架构 企业号9月PK榜

一文浅谈Mockito使用 | 京东云技术团队

京东科技开发者

测试 Mockito Mock 企业号9月PK榜

后端服务之应用预热 | 京东云技术团队

京东科技开发者

JS防抖 抖动 jsf 企业号9月PK榜 应用预热

人工智能的催化剂:GPU高性能计算

青椒云云电脑

人工智能 gpu GPU算力 AI绘画

怎么选择适合深度学习的GPU

青椒云云电脑

云桌面 AI绘画 云桌面系统

GPU应用:从计算机图形学到人工智能

青椒云云电脑

人工智能 gpu AI绘画

为什么GPU引领加速计算时代

青椒云云电脑

GPU算力

艺术与区块链的融合—NFT开发的创意之旅

区块链软件开发推广运营

交易所开发 dapp开发 区块链开发 链游开发 NFT开发

可观测性成熟度模型介绍(一)

乘云数字DataBuff

第六周作业

大肚皮狒狒

DeFi/DApp单双币/子母币流动性质押LP挖矿项目系统开发

l8l259l3365

Python Web框架

为什么GPU在深度学习扮演重要角色?

青椒云云电脑

gpu

GPT 被曝重大缺陷;腾讯侦破国内首个 AI 游戏外挂;特斯拉人形机器人再进化丨 RTE 开发者日报 Vol.56

声网

QCN9074, QCN9274, QCN6274 - Wi-Fi 6E bands: 2.4 GHz, 5 GHz and 6 GHz

wifi6-yiyi

QCN9074 Wi-Fi 6E

国产化运维安全审计系统哪家好?支持信创吗?有哪些功能?

行云管家

国产化 安全运维 运维审计 国产化平台

3D设计软件Rhinoceros 6 mac(犀牛6中文直装)完美激活版

mac

windows 三维建模软件 苹果mac Rhinoceros 犀牛6

支付宝小程序云,智能开放的增长引擎

TRaaS

支付宝小程序 AI 大模型

人工智能、GPU与云计算的关系和应用

青椒云云电脑

人工智能 GPU算力 AI绘画

【PPT下载】杭州 Atlassian 社区四周年活动

跟YY哥学Jira

Jira ACE #研发效能 Atlassiam Jira Service Management

九章云极DataCanvas公司入选人工智能融合发展与安全应用典型案例

九章云极DataCanvas

Vulkan并发机制

江湖修行

android 前端 opengl 渲染 vulkan

GPU云服务器有什么优势?

青椒云云电脑

GPU云桌面

一文读懂GPU参数选择

青椒云云电脑

云桌面 GPU算力

ReactiveCocoa - iOS开发的新框架_QCon_唐巧_InfoQ精选文章