ReactiveCocoa(簡稱為RAC),是由Github開源的一個應用于iOS和OS開發(fā)的框架.
RAC 的核心思想:創(chuàng)建信號 - 訂閱信號 - 發(fā)送信號 我們按照這個步驟來 一步一步的實現(xiàn) 并且探尋RAC 里面是怎么的一個原理
信號寫法
- 第一種寫法
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"創(chuàng)建信號");
//發(fā)送信號
[subscriber sendNext:array];
return nil;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱信號%@",x);
}];
- 第二種寫法 上面的方式縮寫
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"創(chuàng)建信號");
//發(fā)送信號
[subscriber sendNext:array];
return nil;
}]subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱信號%@",x);
}];
- 為了便于理解 我們先按照順序分步驟寫 探尋每個方法里面的秘密
創(chuàng)建信號 內(nèi)部的秘密
- 如我們下面這行代碼,就是創(chuàng)建信號。RACSignal 的類方法createSignal,帶block回調(diào),里面有一個參數(shù)RACSubscriber。整個方法返回一個RACSignal對象。 創(chuàng)因為沒有訂閱者。稱為冷信號
RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"創(chuàng)建信號");
return nil;
}];
下面我們進入 createSignal方法看看里面怎么實現(xiàn)的
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
看到createSignal方法里面 創(chuàng)建了一個 RACDynamicSignal對象,我們可以把它理解為一個動態(tài)信號。同時對一個didSubscribe這個block 進行了一個保存
訂閱信號 內(nèi)部的秘密
- 訂閱信號 RACSignal 對象 調(diào)用一個方法 subscribeNext,方法 返回一個RACDisposable對象(可以先不看這個) ,寫了subscribeNext 方法的信號,因為有了訂閱者稱為熱信號。
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱信號%@",x);
}];
下面我們進入 subscribeNext 方法看看 里面有什么
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
//進入subscriberWithNext方法
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
RACSubscriber *subscriber = [[self alloc] init];
subscriber->_next = [next copy];
subscriber->_error = [error copy];
subscriber->_completed = [completed copy];
return subscriber;
}
看到 subscribeNext里 調(diào)用subscriberWithNext里面 創(chuàng)建了一個 RACSubscriber 對象(這是一個有意思的現(xiàn)象 ,在上面 創(chuàng)建信號的里面 我們見到了 創(chuàng)建方法里 保存了一個didSubscribe block 也是RACSubscriber,它的實質(zhì)就是創(chuàng)建信號的block)。同時 對 _next _error _completed 三個block 進行了保存 并執(zhí)行了RACSubscriber
發(fā)送信號 內(nèi)部的秘密
- 就一句簡單 sendNext: 如果沒有這句,我是訂閱者是沒法獲取數(shù)據(jù)的
// 發(fā)送信號
[subscriber sendNext:@“我是內(nèi)容”];
下面我們進入 sendNext 方法看看 里面有什么
sendNext 在 多個類都有此方法
點擊 RACSubject sendNext:
里面是醬紫的
- (void)sendNext:(id)value {
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
}
調(diào)用 [RACSubject sendNext] 時
RACSubject就會遍歷一遍自己的subcribers數(shù)組,并調(diào)用各數(shù)組元素(subscriber)準備好的Block
繼續(xù)點擊RACSubscriber sendNext
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
又見到了 熟悉的面孔 上面 訂閱信號保存的一個_next block ,
把 之前在訂閱信號保存的_next block 進行賦值并執(zhí)行。
整理一下
看了一會 這么多方法,這些貌似有聯(lián)系,但是又模模糊糊的。我們和代碼結(jié)合起來看
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
一. //創(chuàng)建信號
1.創(chuàng)建了一個 RACDynamicSignal
2.保存了一個 didSubscribe block
RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"創(chuàng)建信號");
三.//發(fā)送信號
1.執(zhí)行訂閱信號保存的_next block 。
[subscriber sendNext:array];
return nil;
}];
二.//訂閱信號
1.保存了_next _error _completed 三個block
2.執(zhí)行創(chuàng)建信號時所保存的didSubscribe block
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"訂閱信號%@",x);
}];
看了大約能明白 都是block 在互相關聯(lián)
我們在用圖了解一些整個信號的運行原理
創(chuàng)建信號 - 訂閱信號 - 發(fā)送信號 就是這樣實現(xiàn)的
不得不佩服ReactiveCocoa 的作者們,給我們在開啟了一座新的大門。它的編程思想真的值得我們?nèi)W習一下。
結(jié)尾:水平有限,代碼也很爛,一直在努力學習中,大家多多包涵。