1.ReactiveCocoa简介
ReactiveCocoa(简称为RAC
),是由Github
开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。
2.ReactiveCocoa作用
- 在我们iOS开发过程中,当某些事件响应的时候,需要处理某些业务逻辑,这些事件都用不同的方式来处理。
- 比如按钮的点击使用action,ScrollView滚动使用delegate,属性值改变使用KVO等系统提供的方式。
- 其实这些事件,都可以通过RAC处理
- ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把要处理的事情,和监听的事情的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中
高聚合,低耦合
的思想。
3.编程思想
在开发中我们也不能太依赖于某个框架,否则这个框架不更新了,导致项目后期没办法维护,比如之前Facebook提供的Three20框架
,在当时也是神器,但是后来不更新了,也就没什么人用了。因此我感觉学习一个框架,还是有必要了解它的编程思想
。
编程思想的由来
:在开发中我们会遇见各种各样的需求,经常会思考如何快速的完成这些需求,这样就会慢慢形成快速完成这些需求的思想。
先简单介绍下目前咱们已知的编程思想
。
3.1 面向过程
:处理事情以过程为核心,一步一步的实现。
3.2 面向对象
:万物皆对象
3.3 链式编程思想
:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3)
链式编程特点
:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)代表
:masonry框架。
// 创建红色view
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
// 设置约束,一定要先把view添加上去,才能设置约束
[redView mas_makeConstraints:^(MASConstraintMaker *make) {
// 链式编程思想特点:方法返回值必须要方法调用者
// block:把需要操作的值当做block参数,block也需要返回值,就是方法调用者
// 设置约束
// 给make添加left,top约束,调用equalTo给这两个约束赋值
make.left.top.equalTo(@10);
make.right.bottom.equalTo(@-10);
}];
/*
mas_makeConstraints执行流程:
1.创建约束制造者MASConstraintMaker,绑定控件,生成了一个保存所有约束的数组
2.执行mas_makeConstraints传入进行的block
3.让约束制造者安装约束
* 1.清空之前的所有约束
* 2.遍历约束数组,一个一个安装
*/
-
练习一
:模仿masonry,写一个加法计算器,练习链式编程思想。
// CalculateManager.h
#import <Foundation/Foundation.h>
@interface CalculateManager : NSObject
@property (nonatomic, assign) int result;
//- (instancetype)add:(int)value;
- (CalculateManager *(^)(int))add;
@end
#import "CalculateManager.h"
@implementation CalculateManager
- (CalculateManager * (^)(int))add
{
return ^(int value){
_result += value;
return self;
};
}
@end
#import <Foundation/Foundation.h>
#import "CalculateManager.h"
@interface NSObject (Calculate)
/*
方法设计:自己框架,最好添加一个方法前缀
*/
// 把所有的计算代码放在这里
+ (int)ZJY_makeCalculate:(void(^)(CalculateManager *))block;
@end
#import "NSObject+Calculate.h"
#import "CalculateManager.h"
@implementation NSObject (Calculate)
+ (int)ZJY_makeCalculate:(void (^)(CalculateManager *))block
{
// 创建计算管理者
CalculateManager *mgr = [[CalculateManager alloc] init];
// 执行计算
block(mgr);
return mgr.result;
}
@end
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
int reslut = [NSObject ZJY_makeCalculate:^(CalculateManager *mgr) {
// 在这个里面存放计算代码
// 5 + 5
// mgr.add(5).add(5).multy(5).sub(10);
// [[mgr add:5] add:5];
// 5 + 6 + 7 = 18
mgr.add(5).add(6).add(7);
}];
NSLog(@"%d",reslut);
}
3.4 响应式编程思想
:不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。
代表
:KVO运用。练习二
:KVO底层实现。
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
@public
NSString *_name;
}
/** */
@property (nonatomic, strong) NSString *name;
@end
#import "Person.h"
@implementation Person
- (void)setName:(NSString *)name
{
_name = [NSString stringWithFormat:@"%@aaaa",name];
}
@end
ZJYKVONotifying_Person.h
#import "Person.h"
@interface ZJYKVONotifying_Person : Person
@end
#import "ZJYKVONotifying_Person.h"
#import <objc/message.h>
extern NSString *const observerKey ;
@implementation ZJYKVONotifying_Person
- (void)setName:(NSString *)name
{
[super setName:name];
// 通知观察者调用observeValueForKeyPath
// 需要把观察者保存到当前对象
// 获取观察者
id obsetver = objc_getAssociatedObject(self, observerKey);
[obsetver observeValueForKeyPath:@"name" ofObject:self change:nil context:nil];
}
@end
// NSObject+KVO.h
#import <Foundation/Foundation.h>
@interface NSObject (KVO)
- (void)ZJY_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end
#import "NSObject+KVO.h"
#import <objc/message.h>
#import "ZJYKVONotifying_Person.h"
NSString *const observerKey = @"observer";
@implementation NSObject (KVO)
// 监听某个对象的属性
// 谁调用就监听谁
- (void)ZJY_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
{
/*
// 1.自定义NSKVONotifying_Person子类
// 2.重写setName,在内部恢复父类做法,通知观察者
// 3.如何让外界调用自定义Person类的子类方法,修改当前对象的isa指针,指向NSKVONotifying_Person
*/
// 把观察者保存到当前对象
objc_setAssociatedObject(self, (__bridge const void *)(observerKey), observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// 修改对象isa指针
object_setClass(self, [ZJYKVONotifying_Person class]);
}
@end
// ViewController.m
#import "ViewController.h"
#import "Person.h"
#import "NSObject+KVO.h"
@interface ViewController ()
@property (nonatomic, strong) Person *p;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// KVO底层实现
// 1.自定义NSKVONotifying_Person子类
// 2.重写setName,在内部恢复父类做法,通知观察者
// 3.如何让外界调用自定义Person类的子类方法,修改当前对象的isa指针,指向NSKVONotifying_Person
Person *p = [[Person alloc] init];
// 监听name属性有没有改变
[p ZJY_addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
// [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
_p = p;
}
- (void)KVO
{
/*
响应式编程思想
a,b,c
c = a + b;
a = 2;
b = 3;
*/
Person *p = [[Person alloc] init];
// 监听name属性有没有改变
[p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
_p = p;
// KVO怎么实现
// KVO的本质就是监听一个对象有没有调用set方法
// 重写这个方法
// 监听方法本质:并不需要修改方法的实现,仅仅想判断下有没有调用
}
// 只要p.name一改变就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
NSLog(@"%@",_p.name);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
static int i = 0;
i++;
_p.name = [NSString stringWithFormat:@"%d",i];
// _p -> _name = [NSString stringWithFormat:@"%d",i];
}
@end
3.5 函数式编程思想
:是把操作尽量写成一系列嵌套的函数或者方法调用。
函数式编程本质
:就是往方法中传入Block,方法中嵌套Block调用,把代码聚合起来管理函数式编程特点
:每个方法必须有返回值(本身对象),把函数或者Block当做参数,block参数(需要操作的值)block返回值(操作结果)代表
:ReactiveCocoa。练习三
:用函数式编程实现,写一个加法计算器,并且加法计算器自带判断是否等于某个值.
// CalculateManager.h
#import <Foundation/Foundation.h>
@interface CalculateManager : NSObject
@property (nonatomic, assign) int result;
// 计算
- (instancetype)calculate:(int(^)(int))calculateBlock;
@end
#import "CalculateManager.h"
@implementation CalculateManager
- (instancetype)calculate:(int (^)(int))calculateBlock
{
_result = calculateBlock(_result);
return self;
}
@end
#import "ViewController.h"
#import "CalculateManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CalculateManager *mgr = [[CalculateManager alloc] init];
int result = [[mgr calculate:^(int result){
// 存放所有的计算代码
result += 5;
result *= 5;
return result;
}] result];
NSLog(@"%d",result);
}
4.ReactiveCocoa编程思想
ReactiveCocoa结合了几种编程风格:
函数式编程(Functional Programming)
响应式编程(Reactive Programming)
所以,你可能听说过ReactiveCocoa被描述为函数响应式编程(FRP)框架。
以后使用RAC解决问题,就不需要考虑调用顺序,直接考虑结果,把每一次操作都写成一系列嵌套的方法中,使代码高聚合,方便管理。
5.如何导入ReactiveCocoa框架
通常都会使用CocoaPods(用于管理第三方框架的插件)帮助我们导入。
PS:CocoaPods教程(http://code4app.com/article/cocoapods-install-usage)
练习四
:创建一个新的工程,演示下,框架的导入。
注意
:
- podfile如果只描述pod 'ReactiveCocoa', '~> 4.0.2-alpha-1',会导入不成功
- 报错信息
- 需要在podfile加上use_frameworks,重新pod install 才能导入成功。
满地打滚卖萌求赞,如果本文帮助到你,轻点下方的红心,给作者君增加更新的动力。