iOS_42_RAC

ReactiveCocoa(其简称为 RAC)是由 Github 开源的一个应用于 iOS 和 OS X 开发的新框架。RAC 具有函数式编程和响应式编程的特性(FRP:函数响应式编程)。它主要吸取了 .Net 的 Reactive Extensions 的设计和实现。

 

 

资料:http://blog.devtang.com/2016/01/03/reactive-cocoa-discussion/

 

block用strong(非ARC用copy)

 

 

 

1.ReactiveCocoa简介

 

ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。

2.ReactiveCocoa作用

在我们iOS开发过程中,经常会响应某些事件来处理某些业务逻辑,例如按钮的点击,上下拉刷新,网络请求,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback等。

其实这些事件,都可以通过RAC处理,ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把要处理的事情,和监听的事情的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中高聚合,低耦合的思想。

3.编程思想

在开发中我们也不能太依赖于某个框架,否则这个框架不更新了,导致项目后期没办法维护,比如之前Facebook提供的Three20框架,在当时也是神器,但是后来不更新了,也就没什么人用了。因此我感觉学习一个框架,还是有必要了解它的编程思想

先简单介绍下目前咱们已知的编程思想

3.1 面向过程:处理事情以过程为核心,一步一步的实现。

3.2 面向对象:万物皆对象

3.3 链式编程思想:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3)

  • 链式编程特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)

  • 代表:masonry框架。

  • 练习一:模仿masonry,写一个加法计算器,练习链式编程思想。

3.4 响应式编程思想:不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。

  • 代表:KVO运用。

  • 练习二:KVO底层实现。

3.5 函数式编程思想:是把操作尽量写成一系列嵌套的函数或者方法调用。

  • 函数式编程本质:就是往方法中传入Block,方法中嵌套Block调用,把代码聚合起来管理
  • 函数式编程特点:每个方法必须有返回值(本身对象),把函数或者Block当做参数,block参数(需要操作的值)block返回值(操作结果)

  • 代表:ReactiveCocoa。

  • 练习三:用函数式编程实现,写一个加法计算器,并且加法计算器自带判断是否等于某个值.

4.ReactiveCocoa编程思想

ReactiveCocoa结合了几种编程风格:

函数式编程(Functional Programming)

响应式编程(Reactive Programming)

所以,你可能听说过ReactiveCocoa被描述为函数响应式编程(FRP)框架。

以后使用RAC解决问题,就不需要考虑调用顺序,直接考虑结果,把每一次操作都写成一系列嵌套的方法中,使代码高聚合,方便管理。

 

 

 

 

 

1 .Masonry的链式思想:将多个操作(多行代码)通过点号.()链接在一起成为一句代码,代码的可读性好,如a(1).b(2).c(3)

链式编程特点:方法的返回值是block, block必须有返回值(本身对象),block的参数(需要操作的数值)

 

 

//
//  ViewController.m
//  01mansonry
//
//  Created by beyond on 2017/12/8.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "ViewController.h"
// 拖入Masonry文件夹
#import "Masonry.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *redView = [[UIView alloc]init];
    redView.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1];
    [self.view addSubview:redView];// 居中的长方形 
    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.equalTo(@10);
        make.right.bottom.equalTo(@-10);
    }];
}




@end

 

 

 

 

 

2 .Masonry的链式思想实现的计算器示例

 

 

//
//  ViewController.m
//  02Calculator
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "ViewController.h"
#import "NSObject+Calculator.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建一个分类,使得任何类都可以用类方法,进行计算
    int result = [NSObject makeCalculator:^(CalculatorMaker *maker) {
        maker.add(1).add(20).multiply(3);
    }];
    NSLog(@"sg__%d",result);
}



@end

 

//
//  NSObject+Calculator.h
//  02Calculator
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "CalculatorMaker.h"
@interface NSObject (Calculator)
+(int)makeCalculator:(void (^)(CalculatorMaker *))block;
@end
//
//  NSObject+Calculator.m
//  02Calculator
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "NSObject+Calculator.h"

@implementation NSObject (Calculator)
+(int)makeCalculator:(void (^)(CalculatorMaker *))block
{
    // 创建一个计算器
    CalculatorMaker *maker = [[CalculatorMaker alloc]init];
    // 将计算器传递给外部 控制器,并且计算器会在内部自动处理result
    block(maker);
    // 返回处理后的结果 
    return maker.result;
}
@end

 

 

 

 

 

//
//  CalculatorMaker.h
//  02Calculator
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface CalculatorMaker : NSObject
@property (nonatomic,assign) int result;
// 加法:返回block (block的返回值是CalculatorMaker自身,参数是参与运算的值)
- (CalculatorMaker * (^)(int num))add;


// 乘法:返回block (block的返回值是CalculatorMaker自身,参数是参与运算的值)
- (CalculatorMaker * (^)(int num))multiply;
@end

 

//
//  CalculatorMaker.m
//  02Calculator
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "CalculatorMaker.h"

@implementation CalculatorMaker
// 返回block (block的返回值是CalculatorMaker自身,参数是参与运算的值)
- (CalculatorMaker * (^)(int num))add
{
    return ^(int num){
        // 参与运算后,保存在成员变量_result内
        _result += num;
        return self;
    };
}



// 返回block (block的返回值是CalculatorMaker自身,参数是参与运算的值)
- (CalculatorMaker *(^)(int num))multiply
{
    return ^(int num){
        // 参与运算后,保存在成员变量_result内
        _result *= num;
        return self;
    };
}
@end

 

 

 

 

 

3 .响应式编程,如KVO,不需要考虑调用顺序,类似蝴蝶效应,产生一个事件,会自发地影响很多东西,像流一样的传播开去,然后影响结果.万物皆是流.

KVO底层实现:
1.动态创建新类:NSKVONotifying_Person,NSKVONotifying_Person是Person子类,以作KVO用
2.修改当前对象p的isa指针->NSKVONotifying_Person
3.只要调用对象p的set,就会调用新类的NSKVONotifying_Person的set方法
4.重写新类NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变
    
    // 就是去判断有没有调用一个对象的set方法

 

 

//
//  Person.h
//  03KVO
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    // 只有指定为public之后,才可以直接使用->访问
    @public int _age;
}

@property (nonatomic,assign) int age;
@end

 

 

 

 

 

 

//
//  ViewController.m
//  03KVO
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "ViewController.h"
// 触摸屏幕一下,年纪age++,通知观察者,在代理方法中打印变化的age
#import "Person.h"

@interface ViewController ()

@property (nonatomic,strong)Person *p;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *p = [[Person alloc]init];
    _p = p;
    
    // 添加观察者
    [p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
    
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"sg__%d",_p.age);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 每点击次一屏幕,就调用set方法,改变age;
    // _p.age ++;
    _p->_age ++; // 不会触发,因为没有执行set方法
}
@end

 

 

 

 

 

 

 

 

 

 

 

4.仿造KVO的实现

 

//
//  ViewController.m
//  03KVO
//
//  Created by beyond on 2017/12/10.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "ViewController.h"
// 触摸屏幕一下,年纪age++,通知观察者,在代理方法中打印变化的age
#import "Person.h"
#import "NSObject+KVO.h"
@interface ViewController ()

@property (nonatomic,strong)Person *p;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *p = [[Person alloc]init];
    _p = p;
    
    // 使用自己的KVO,添加观察者
    [p sg_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
    
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"sg__%d",_p.age);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 每点击次一屏幕,就调用set方法,改变age;
    _p.age ++;
    // _p->_age ++; // 不会触发,因为没有执行set方法
}
@end

 

 

 

 

 

 

继承自Person的类

 

//
//  SGKVONotifying_Person.h
//  03KVO
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "Person.h"

@interface SGKVONotifying_Person : Person

@end

 

//
//  SGKVONotifying_Person.m
//  03KVO
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "SGKVONotifying_Person.h"
#import <objc/runtime.h>
@implementation SGKVONotifying_Person
// 自己实现KVO的底层
- (void)setAge:(int)age
{
    // 1.正常赋值
    [super setAge:age];
    
    // 2.当age值改变的时候,通过运行时获取前面保存的观察者
    id observer_ctrl = objc_getAssociatedObject(self, "observer_ctrl");
    // 3.调用观察者observer_ctrl的方法,告知age已改变
    [observer_ctrl observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
}
@end

 

 

 

 

 

通过一个NSObject的分类,自己实现的addObserver方法

 

//
//  NSObject+KVO.h
//  03KVO
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSObject (KVO)
// 添加分类,自己实现一个addObserver方法
- (void)sg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end

 

 

 

 

 

 

//
//  NSObject+KVO.m
//  03KVO
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "NSObject+KVO.h"

// 修改isa指针时,保存观察者时用到运行时
#import <objc/runtime.h>

@implementation NSObject (KVO)
// 添加分类,自己实现一个addObserver方法
- (void)sg_addObserver:(NSObject *)observer_ctrl forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context
{
//    KVO底层实现:
//    1.动态创建新类:NSKVONotifying_Person,NSKVONotifying_Person是Person子类,以作KVO用
//    2.修改当前对象p的isa指针->NSKVONotifying_Person
//    3.只要调用对象p的set,就会调用新类的NSKVONotifying_Person的set方法
//    4.重写新类NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变
    
    
    //1.改变isa指向自己实现KVO用到的的一个Person的子类
    object_setClass(self, NSClassFromString(@"SGKVONotifying_Person"));
    //2.给分类关联一个新的成员变量
    objc_setAssociatedObject(self, "observer_ctrl", observer_ctrl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
}
@end

 

 

 

 

 

 

5.函数式编程:把操作尽量写成一系列嵌套的函数或方法调用.

特点:1.每个方法必须有返回值(本身对象),

2.把函数或者block当成参数.

3.block的参数是需要操作的变量

4.block的返回值是操作完成后的结果

 

 

//
//  ViewController.m
//  04函数式编程
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "ViewController.h"
#import "Calculator.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Calculator *calc = [[Calculator alloc]init];
    
    /*
     函数式编程:把操作尽量写成一系列嵌套的函数或方法调用.
     特点:1.每个方法(如下面的add方法)必须有返回值(本身对象),
     2.把函数或者block当成参数.
     3.block的参数是需要操作的成员变量
     4.block的返回值是操作完成后的结果
     */
    int output = [[calc add:^int(int result) {
        result += 1;
        result += 20;
        // 返回block操作完成后的值(目的是用于保存到成员变量里)
        return result;
    }] result];
    NSLog(@"sg_%d",output);
}




@end

 

 

 

 

 

 

//
//  Calculator.h
//  04函数式编程
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Calculator : NSObject
@property (nonatomic,assign)int result;

// 返回值是本身
// 参数是一个block;
// block的参数是外部控制器要操作的成员变量result
// block的返回值是外部控制器操作完成后的结果数值
- (instancetype)add:(int (^)(int result))block;
@end

 

 

 

 

 

 

//
//  Calculator.m
//  04函数式编程
//
//  Created by beyond on 2017/12/11.
//  Copyright © 2017年 beyond. All rights reserved.
//

#import "Calculator.h"

@implementation Calculator
/*
 函数式编程:把操作尽量写成一系列嵌套的函数或方法调用.
 特点:1.每个方法(如下面的add方法)必须有返回值(本身对象),
 2.把函数或者block当成参数.
 3.block的参数是需要操作的成员变量
 4.block的返回值是操作完成后的结果
 */


// add方法:返回值是本身
// add方法:参数是一个block;
// block的参数是外部控制器要操作的成员变量result
// block的返回值是外部控制器操作完成后的结果数值
- (instancetype)add:(int (^)(int result))block
{
    //直接调用外部控制器的block,并且把外部控制器要操作的本类的成员变量传递进去,并且把block的返回值保存在成员变量里
    _result = block(_result);
    
    
    // 返回本身
    return self;
}
@end

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值