日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ReactiveCocoa源码解读(二)

發布時間:2025/7/14 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ReactiveCocoa源码解读(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇解讀了ReactiveCocoa的三個重要的類的底層實現,本篇繼續。

一、RACMulticastConnection

1.應用

RACMulticastConnection: 用于當一個信號被多次訂閱時,為了保證創建信號時,避免多次調用創建信號的block造成副作用,可以使用該類處理,保證創建信號的block執行一次。

// 創建信號 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {NSLog(@"發送請求");[subscriber sendNext:@1];return nil; }];// 創建連接 RACMulticastConnection *connect = [signal publish];// 訂閱連接的信號 [connect.signal subscribeNext:^(id x) {NSLog(@"connect 第一次訂閱信號: %@", x); }];[connect.signal subscribeNext:^(id x) {NSLog(@"connect 第二次訂閱信號: %@", x); }];// 連接 [connect connect];

2.源碼實現

  • 底層原理
1.創建connect,connect.sourceSignal -> RACSignal(原始信號) connect.signal -> RACSubject 2.訂閱connect.signal,會調用RACSubject的subscribeNext,創建訂閱者,而且把訂閱者保存起來,不會執行block。 3.[connect connect]內部會訂閱RACSignal(原始信號),并且訂閱者是RACSubject3.1.訂閱原始信號,就會調用原始信號中的didSubscribe3.2 didSubscribe,拿到訂閱者調用sendNext,其實是調用RACSubject的sendNext 4.RACSubject的sendNext,會遍歷RACSubject所有訂閱者發送信號。4.1 因為剛剛第二步,都是在訂閱RACSubject,因此會拿到第二步所有的訂閱者,調用他們的nextBlock
  • 創建信號

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe

// RACDynamicSignal.m + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe {RACDynamicSignal *signal = [[self alloc] init];//將代碼塊保存到信號里面(但此時僅僅是保存,沒有調用),所以信號還是冷信號signal->_didSubscribe = [didSubscribe copy];return [signal setNameWithFormat:@"+createSignal:"]; }
  • 創建連接

[signal publish]

// RACSignal+Operations.m - (RACMulticastConnection *)publish {// 創建訂閱者RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];// 創建connection,參數是剛才創建的訂閱者RACMulticastConnection *connection = [self multicast:subject];return connection; }- (RACMulticastConnection *)multicast:(RACSubject *)subject {[subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];return connection; }// RACMulticastConnection.m - (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {NSCParameterAssert(source != nil);NSCParameterAssert(subject != nil);self = [super init];if (self == nil) return nil;// 保存原始信號_sourceSignal = source;_serialDisposable = [[RACSerialDisposable alloc] init];// 保存訂閱者,即_signal是RACSubject對象_signal = subject;return self; }
  • 訂閱信號

(RACDisposable *)subscribeNext:(void (^ )(id x))nextBlock;

// RACSignal.m - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {NSCParameterAssert(nextBlock != NULL);RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];return [self subscribe:o]; }// RACSubscriber.m + (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; }// RACSubject.m - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {NSCParameterAssert(subscriber != nil);RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];NSMutableArray *subscribers = self.subscribers;@synchronized (subscribers) {[subscribers addObject:subscriber];}return [RACDisposable disposableWithBlock:^{@synchronized (subscribers) {// Since newer subscribers are generally shorter-lived, search// starting from the end of the list.NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {return obj == subscriber;}];if (index != NSNotFound) [subscribers removeObjectAtIndex:index];}}]; }
  • 連接信號

[connect connect];

// RACMulticastConnection.m - (RACDisposable *)connect {BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);if (shouldConnect) {// 訂閱原生信號self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];}return self.serialDisposable; }// RACDynamicSignal.m - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {NSCParameterAssert(subscriber != nil);RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];if (self.didSubscribe != NULL) {RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{RACDisposable *innerDisposable = self.didSubscribe(subscriber);[disposable addDisposable:innerDisposable];}];[disposable addDisposable:schedulingDisposable];}return disposable; }// RACSubject.m - (void)sendNext:(id)value {// 遍歷_subscribers數組,執行nextBlock[self enumerateSubscribersUsingBlock:^(id subscriber) {[subscriber sendNext:value];}]; }

3.流程圖

4.總結

RACMulticastConnection利用RACSubject實現了創建信號的block只執行一次的功能。對于需要對此訂閱信號,但是不希望多次創建信號的應用場合,可以RACMulticastConnection解決。

二、RACCommand

1.應用

RACCommand類用來表示動作的執行, 是對動作觸發后的連鎖事件的封裝。常用在封裝網絡請求,按鈕點擊等等場合。

RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {return [RACSignal createSignal:^RACDisposable *(id subscriber) {if (/* DISABLES CODE */ (YES)) {// 正常發送數據,必須發送完成信號[subscriber sendNext:@"Smile"];[subscriber sendCompleted];} else {// 發送錯誤信號[subscriber sendError:[NSError errorWithDomain:@"Network failed" code:0005 userInfo:nil]];}// 信號被銷毀前,做一些清理的工作;如果不需要,可以 return nilreturn [RACDisposable disposableWithBlock:^{NSLog(@"信號被銷毀了");}];}]; }];// 執行信號并訂閱 [[command execute:nil] subscribeNext:^(id x) {NSLog(@"receive data: %@", x); }];

2.源碼實現

RACCommand底層實現

1. 創建命令,保存signalBlock 2. 執行命令 * 2.1 調用signalBlock * 2.2 創建connect,傳入RACReplaySubject對象,然后連接信號 3. 訂閱信號 * 3.1 創建訂閱者,保存到RACReplaySubject對象的_subscribers數組中 * 3.2 遍歷valuesReceived數組,調用訂閱者發送數據
  • 創建command

- (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock

// RACCommand.m - (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock {return [self initWithEnabled:nil signalBlock:signalBlock]; }- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock {NSCParameterAssert(signalBlock != nil);self = [super init];if (self == nil) return nil;_activeExecutionSignals = [[NSMutableArray alloc] init];// 保存創建信號的block_signalBlock = [signalBlock copy];...... }
  • 執行command

- (RACSignal *)execute:(id)input

// RACCommand.m - (RACSignal *)execute:(id)input {// `immediateEnabled` is guaranteed to send a value upon subscription, so// -first is acceptable here.BOOL enabled = [[self.immediateEnabled first] boolValue];if (!enabled) {NSError *error = [NSError errorWithDomain:RACCommandErrorDomain code:RACCommandErrorNotEnabled userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The command is disabled and cannot be executed", nil),RACUnderlyingCommandErrorKey: self}];return [RACSignal error:error];}RACSignal *signal = self.signalBlock(input);......// 創建連接,用RACReplaySubject作為訂閱者RACMulticastConnection *connection = [[signalsubscribeOn:RACScheduler.mainThreadScheduler]multicast:[RACReplaySubject subject]];......// 連接信號[connection connect];return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, [input rac_description]]; }// RACMulticastConnection.m - (RACDisposable *)connect {BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &amp;_hasConnected);if (shouldConnect) {// 執行創建信號的blockself.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];}return self.serialDisposable; }
  • 訂閱command

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock

// RACSignal.m - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {NSCParameterAssert(nextBlock != NULL);RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];return [self subscribe:o]; }// RACReplaySubject.m - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{@synchronized (self) {for (id value in self.valuesReceived) {if (compoundDisposable.disposed) return;// 調用訂閱者,發送數據 "Smile"[subscriber sendNext:(value == RACTupleNil.tupleNil ? nil : value)];}if (compoundDisposable.disposed) return;if (self.hasCompleted) {[subscriber sendCompleted];} else if (self.hasError) {[subscriber sendError:self.error];} else {// 調用父類方法,保存訂閱者到_subscribers數組RACDisposable *subscriptionDisposable = [super subscribe:subscriber];[compoundDisposable addDisposable:subscriptionDisposable];}}}];[compoundDisposable addDisposable:schedulingDisposable];return compoundDisposable; }

3.流程圖

4.總結

RACCommand用來封裝事件時,還可以訂閱信號(executionSignals)、訂閱最新信號(switchToLatest)、跳過幾次信號(skip)或信號是否正在執行(executing),在執行信號時,還可以監聽錯誤信號和完成信號,請參考demo例子。


ReactiveCocoa框架的源碼分析暫告一段落,如有分析不足之處,歡迎互相交流。

Demo地址:

RACDemo

轉載于:https://www.cnblogs.com/fishbay/p/7206768.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的ReactiveCocoa源码解读(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。