1.ReactiveCocoa簡介
ReactiveCocoa(簡稱為RAC),是由Github開源的一個應(yīng)用于iOS和OS開發(fā)的新框架,Cocoa是蘋果整套框架的簡稱,因此很多蘋果框架喜歡以Cocoa結(jié)尾骗卜。
2.ReactiveCocoa作用
在我們iOS開發(fā)過程中,經(jīng)常會響應(yīng)某些事件來處理某些業(yè)務(wù)邏輯闲坎,例如按鈕的點擊旺垒,上下拉刷新寨躁,網(wǎng)絡(luò)請求宛裕,屬性的變化(通過KVO)或者用戶位置的變化(通過CoreLocation)瑟啃。但是這些事件都用不同的方式來處理,比如action揩尸、delegate蛹屿、KVO、callback等疲酌。
其實這些事件蜡峰,都可以通過RAC處理,ReactiveCocoa為事件提供了很多處理方法朗恳,而且利用RAC處理事件很方便湿颅,可以把要處理的事情,和監(jiān)聽的事情的代碼放在一起粥诫,這樣非常方便我們管理油航,就不需要跳到對應(yīng)的方法里。非常符合我們開發(fā)中高聚合怀浆,低耦合的思想谊囚。
3.編程思想
在開發(fā)中我們也不能太依賴于某個框架,否則這個框架不更新了执赡,導致項目后期沒辦法維護镰踏,比如之前Facebook提供的Three20框架,在當時也是神器沙合,但是后來不更新了奠伪,也就沒什么人用了。因此我感覺學習一個框架首懈,還是有必要了解它的編程思想绊率。
先簡單介紹下目前咱們已知的編程思想。
3.1 面向過程:處理事情以過程為核心究履,一步一步的實現(xiàn)滤否。
3.2 面向?qū)ο螅喝f物皆對象
3.3 鏈式編程思想:是將多個操作(多行代碼)通過點號(.)鏈接在一起成為一句代碼,使代碼可讀性好。a(1).b(2).c(3)
鏈式編程特點:方法的返回值是block,block必須有返回值(本身對象)最仑,block參數(shù)(需要操作的值)
代表:masonry框架藐俺。
練習一:模仿masonry,寫一個加法計算器盯仪,練習鏈式編程思想紊搪。
//
// ViewController.m
// 01-鏈式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "ViewController.h"
#import "NSObject+Calculate.h"
#import "CalculateManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
int result = [NSObject kx_makeCalculate:^(CalculateManager * manager) {
// manager.add(5)
// [[manager add:5] add:5];
//用block替代方法
//把怎么計算的代碼封裝到block中
manager.add(5).add(10);
}];
NSLog(@"%d",result);
}
@end
#pragma mark ------NSObject+Calculate.h文件
// NSObject+Calculate.h
// 01-鏈式編程思想
//
// Created by 徐流洋 on 2017/5/18.
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import <Foundation/Foundation.h>
@class CalculateManager;
@interface NSObject (Calculate)
+ (int )kx_makeCalculate:(void(^)(CalculateManager *manager))block;
@end
#pragma mark -----------------------------------------------
#pragma mark --------NSObject+Calculate.m
// NSObject+Calculate.m
// 01-鏈式編程思想
//
// Created by 徐流洋 on 2017/5/18.
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "NSObject+Calculate.h"
#import "CalculateManager.h"
@implementation NSObject (Calculate)
+ (int)kx_makeCalculate:(void (^)(CalculateManager *))block{
CalculateManager *manager = [[CalculateManager alloc] init];
block(manager);
return manager.result;
}
@end
#pragma mark -----------------------------------------------
#pragma mark ------ CalculateManager.h
// 01-鏈式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface CalculateManager : NSObject
/** 計算結(jié)果 */
@property (nonatomic , assign) int result;
//-(instancetype)add:(int)value;
//返回值必須是類對象本身
- (CalculateManager *(^)(int))add;
@end
#pragma mark -----------------------------------------------
#pragma mark ------ CalculateManager.m
//
// CalculateManager.m
// 01-鏈式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "CalculateManager.h"
@implementation CalculateManager
//-(instancetype)add:(int)value{
//
// _result += value;
//
// return self;
//
//}
-(CalculateManager * (^)(int))add{
return ^(int value){
_result += value;
return self;
};
}
@end
#pragma mark -----------------------------------------------
3.4 響應(yīng)式編程思想:不需要考慮調(diào)用順序,只需要知道考慮結(jié)果全景,類似于蝴蝶效應(yīng)耀石,產(chǎn)生一個事件,會影響很多東西爸黄,這些事件像流一樣的傳播出去滞伟,然后影響結(jié)果,借用面向?qū)ο蟮囊痪湓捒还螅f物皆是流梆奈。
代表:KVO運用。
練習二:KVO底層實現(xiàn)称开。
KVO底層實現(xiàn):就是去判斷有沒有調(diào)用一個對象的set方法
1.首先動態(tài)創(chuàng)建當前對象類的一個派生類(即:子類): NSKVONotifying_Person亩钟,做KVO
2.修改當前對象的isa指針 -> NSKVONotifying_Person
3.只奧調(diào)用對象的set方法乓梨,就會調(diào)用 NSKVONotifying_Person 的set方法
4.重寫 NSKVONotifying_Person 的 set 方法(本質(zhì)賦值)。
4.1:調(diào)用父類賦值[super set:];
4.2:通知觀察者,告訴你屬性改變
KVO底層實現(xiàn)的過程
#pragma mark -------- ViewController.m
// ViewController.m
// 02-響應(yīng)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "ViewController.h"
#import "Person.h"
#import "NSObject+KVO.h"
@interface ViewController ()
/**
*
*/
@property (nonatomic , strong) Person *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc] init];
_person = person;
//給person添加觀察者
[person kx_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
//1.只要 person 的 age 屬性一改變,就會調(diào)用觀察者的 observeValueForKeyPath
//KVO底層實現(xiàn):
//1.首先動態(tài)創(chuàng)建當前對象類的一個派生類(即:子類): NSKVONotifying_Person笙蒙,做KVO
//2.修改當前對象的isa指針 -> NSKVONotifying_Person
//3.只奧調(diào)用對象的set方法浇揩,就會調(diào)用 NSKVONotifying_Person 的set方法
//4.重寫 NSKVONotifying_Person 的 set 方法(本質(zhì)賦值)。
//4.1:調(diào)用父類賦值[super set:];
//4.2:通知觀察者,告訴你屬性改變
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
_person.age++;
}
//只要person.name的值已改變就會調(diào)用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"%d",_person.age);
}
#pragma mark -----------------------------------------------
#pragma mark ----------Person.h
// Person.h
// 02 - 響應(yīng)式編程思想
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Person : NSObject
/** age */
@property (nonatomic , assign) int age;
@end
#pragma mark -----------------------------------------------
#pragma mark ----------NSObject+KVO.h
// NSObject+KVO.h
// 02-響應(yīng)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
#import <Foundation/Foundation.h>
@interface NSObject (KVO)
- (void)kx_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end
#pragma mark -----------------------------------------------
#pragma mark ----------NSObject+KVO.m
//
// NSObject+KVO.m
// 02-響應(yīng)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "NSObject+KVO.h"
#import <objc/message.h>
#import "KXKVONotifying_Person.h"
NSString * const observerKey = @"observer";
@implementation NSObject (KVO)
-(void)kx_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
/**
KVO底層實現(xiàn):
1.首先動態(tài)創(chuàng)建當前對象類的一個派生類(即:子類): KXKVONotifying_Person,做KVO
2.修改當前對象的isa指針 -> KXKVONotifying_Person
3.只奧調(diào)用對象的set方法,就會調(diào)用 KXKVONotifying_Person 的set方法
4.重寫 KXKVONotifying_Person 的 set 方法(本質(zhì)賦值)蝠筑。
4.1:調(diào)用父類賦值[super set:];
4.2:通知觀察者,告訴你屬性改變
*/
//本質(zhì);就是修改當前對象的isa指針的類名
//self:kx_addObserver方法的調(diào)用者即:person
object_setClass(self, [KXKVONotifying_Person class]);
//把觀察者保存到當前對象里(動態(tài)添加屬性)
/**
<#id object#>:給那個對象添加關(guān)聯(lián)
<#const void *key#>:屬性名
<#id value#>:關(guān)聯(lián)值
<#objc_AssociationPolicy policy#>:策略:是assign,retian...
*/
objc_setAssociatedObject(self, (__bridge const void *)(observerKey), observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
#pragma mark -----------------------------------------------
#pragma mark ----------KXKVONotifying_Person.m
// KXKVONotifying_Person.m
// 02-響應(yīng)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "KXKVONotifying_Person.h"
#import <objc/message.h>
extern NSString *const observerKey;
@implementation KXKVONotifying_Person
- (void)setAge:(int)age{
[super setAge:age];
//通知觀察者揩懒,屬性改變
id observer = objc_getAssociatedObject(self, observerKey);
// 調(diào)用觀察者的方法
[observer observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
}
@end
#pragma mark -----------------------------------------------
3.5 函數(shù)式編程思想:是把操作盡量寫成一系列嵌套的函數(shù)或者方法調(diào)用什乙。
函數(shù)式編程本質(zhì):就是往方法中傳入Block,方法中嵌套Block調(diào)用,把代碼聚合起來管理
函數(shù)式編程特點:每個方法必須有返回值(本身對象),把函數(shù)或者Block當做參數(shù),block參數(shù)(需要操作的值)block返回值(操作結(jié)果)
代表:ReactiveCocoa已球。
練習三:用函數(shù)式編程實現(xiàn)稳强,寫一個加法計算器,并且加法計算器自帶判斷是否等于某個值.
#pragma mark -----------ViewController.m
// ViewController.m
// 03-函數(shù)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
/**
* 函數(shù)式編程思想:把一個操作寫成一系列方法
* 需求:寫一個加法計算器,并且加法計算器自帶判斷是否等于某個值
*/
#import "ViewController.h"
#import "Caculator.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Caculator *caculator = [[Caculator alloc] init];
//10 + 20 + 29
// [[[caculator add:10] add:20] add:29];
BOOL isEqule = [[[caculator add:^int(int result) {
//把計算的事情寫到block
result += 10;
result += 30;
result += 20;
result += 40;
return result;
}] equle:^BOOL(int result) {
// 判斷結(jié)果是否 等于 100
return result ==100;
}] isEqule];
NSLog(@"%d",isEqule);
}
@end
#pragma mark -------------------------------
#pragma mark ----------- Caculator.h
//
// Caculator.h
// 03-函數(shù)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Caculator : NSObject
/** 計算結(jié)果 */
@property (nonatomic , assign) int result;
@property (nonatomic , assign) BOOL isEqule;
//- (instancetype)add:(int)num;
- (instancetype)add:(int(^)(int result))block;
- (instancetype)equle:(BOOL(^)(int result))block;
@end
#pragma mark -------------------------------
#pragma mark ---------- Caculator.m
//
// Caculator.m
// 03-函數(shù)式編程思想
//
// Copyright ? 2017年 徐sir. All rights reserved.
//
#import "Caculator.h"
@implementation Caculator
//- (instancetype)add:(int)num{
//
//
// _result += num;
//
// return self;
//
//
//}
- (instancetype)add:(int (^)(int result))block{
_result = block(_result);
return self;
}
- (instancetype)equle:(BOOL (^)(int))block{
_isEqule = block(_result);
return self;
}
@end
#pragma mark -------------------------------
4.ReactiveCocoa編程思想
ReactiveCocoa結(jié)合了幾種編程風格:
函數(shù)式編程(Functional Programming)
響應(yīng)式編程(Reactive Programming)
所以和悦,你可能聽說過ReactiveCocoa被描述為函數(shù)響應(yīng)式編程(FRP)框架退疫。
以后使用RAC解決問題,就不需要考慮調(diào)用順序鸽素,直接考慮結(jié)果褒繁,把每一次操作都寫成一系列嵌套的方法中,使代碼高聚合馍忽,方便管理棒坏。