天天看點

iOS開發筆記之七十四——FRP與RAC進階篇(資料黑白闆ReactiveDataBoard的介紹)一、簡介二、接入說明三、實作原理四、補充說明

******閱讀完此文,大概需要30分鐘******

一、簡介

ReactiveDataBoard是一款已經比較成熟的基于RAC的響應式程式設計元件,它主要用來實作任意子產品之間的資料通訊,它可以替代原生的Notification、KVO,delegate、NSUserdefault等數值傳遞方式。因為它除了可以實時傳遞資料,比起Notification、KVO等,實作相同的功能,ReactiveDataBoard隻需較少的代碼,而且幾乎無需關心Notification和KVO帶來的手動釋放、Crash等問題。使用它,可以很好地提高我們的業務開發效率。目前已經廣泛地使用在VivaVideo家族産品中,得到業務開發的充分肯定與驗證。

元件化代碼位址:

https://github.com/Leon0206/ReactiveDataBoard

二、接入說明

ReactiveDataBoard有兩種資料闆,分别是資料白闆類ReactiveWhiteBoard和資料黑闆類ReactiveBlackBoard,它們實作原理一緻,一個是單例,一個是執行個體化使用,但是用在不同的業務場景,下面分别進行介紹:

1、資料白闆類:ReactiveWhiteBoard

ReactiveWhiteBoard是一個嚴格的單例,app全局隻有一份,推薦在app啟動初始化時進行執行個體化。因為是單例,是以它可以實作記憶體中任意子產品之間的資料實時通訊,具體使用例子如下:

  • 1)資料的訂閱(必須),首先你需要針對某一個key值進行訂閱,代碼如下:
[[RACWB addObserver:self forKey:@"rac_test_key"] subscribeNext:^(id  _Nullable x) {
        NSLog(@"RACMainViewController----->%@",x);
    }];
           

因為傳回是RACSignal,是以它天然就享受了信号帶來的福利;

  • 2)資料的發送(必須),然後你需要對指定的key值進行設定:代碼如下:
[RACWB setValue:@"value" forKey:@"rac_test_key"];
           

其實除了代替Notification,它本身也可以進行記憶體緩存的,它的擷取value的api如下:

- (id _Nullable )valueForKey:(NSString *_Nonnull)key;
           
  • 3) key值資料的移除(可選,但是強烈推薦), 如果你已經完成你的資料傳遞,建議針對key值進行remove,代碼如下:
- (void)removeObserver:(id _Nullable )obj forKey:(NSString *_Nonnull)key;
- (void)removeAllObjObservers:(id _Nullable )obj;
- (void)removeAllKeyObservers:(NSString *_Nullable)key;
           

比起Notification,它的删除API更加靈活;

  • 4) 信号的暫停與重新開機

- (void)pauseSignalForKey:(NSString *_Nullable)key;

- (void)restartSignalForKey:(NSString *_Nonnull)key;

你可以根據業務需要,先暫停以下信号的發送,需要的時候,可以再此restart它;

三、實作原理

ReactiveDataBoard的實作原理不是很複雜,資料黑闆和資料白闆的原理是一樣的,隻是為了适應不同的業務場景才進行區分。

1、ReactiveWhiteBoard的實作

ReactiveWhiteBoard内部維護了兩個字典,observers和values,分别用來存儲訂閱者和要傳遞的值對象;

  • 1)訂閱者代碼分析:
- (RACSignal *)addObserver:(id)obj forKey:(NSString *)key
{
    if (key.length <= 0) return [RACSignal empty];
    @synchronized (self) {
       [self.flags setValue:@(ReactiveBlackBoardFlagOn) forKey:key];
       NSString *insideKey = [NSString stringWithFormat:@"%@_%@_%p",key,NSStringFromClass([obj class]),obj];
       RACSubject *subject = [RACSubject subject];
       [self.observers setValue:subject forKey:insideKey];
       return subject;
    }
}
           

每次訂閱者代碼的執行,都會根據key值生成唯一的RACSubject,RACSubject是一個熱信号,它可以有多個訂閱者,

是以每個key值可以有多個訂閱者,為了可以實作達到Notification的針對不同類以及對象來管理信号,維護一個内部的insideKey,用來便于信号的分組管理。

詳見:

《FRP與RAC介紹(一)》:https://blog.csdn.net/lizitao/article/details/78721650

  • 2)信号發送者代碼分析:

這個就比較簡單了,如下:

- (void)setValue:(id)value forKey:(NSString *)key
{
    if (key.length <= 0) return;
    @synchronized (self.values) {
        [self.values setValue:value forKey:key];
    }
    if (ReactiveBlackBoardFlagOn == [[self.flags valueForKey:key] integerValue]) {
        NSArray *arr = [self subjectsForKey:key];
        [arr enumerateObjectsUsingBlock:^(RACSubject *subject, NSUInteger idx, BOOL * _Nonnull stop) {
            [subject sendNext:value];
        }];
    }
}
           

當執行信号的發送代碼時,首先它會将對應key值的value存儲到self.values中,然後根據擷取的分組keys去取對應的RACSubjects,執行sendNext:操作,根據《FRP與RAC介紹(一)》文中介紹,這一步是在執行訂閱者代碼,并将value傳遞過去。

四、補充說明

  • 1、ReactiveWhiteBoard是基于廣播Notificaiton設計出來的,但是因為它的訂閱者是針對RACSignal進行訂閱的,是以不僅可以享受很多RAC的API帶來的便利,還支援信号的傳遞的暫停與重新開機,于此同時,它也可以作為全局共享記憶體Dictionary去使用,當然,它的信号的删除也更加靈活。
  • 2、能用ReactiveBlackBoard的時候,盡量優先使用ReactiveBlackBoard,簡單的業務場景,通訊資料的比較小,可以用ReactiveWhiteBoard,如果業務場景較複雜,推薦ReactiveBlackBoard。
  • 3、ReactiveWhiteBoard/ReactiveBlackBoard的使用,不要忘記最終的remove操作,雖然它不會帶來像notificaiton和kvo等記憶體洩露問題,但是由于内部字典的不斷增加,最終可能仍會帶來記憶體膨脹的問題。
  • 4、ReactiveWhiteBoard是全局的單例,也就意味着它的block回調會持有變量,是以如果訂閱者回調裡持有self,别忘記__weak __typeof(self) weakSelf = self;
  • 5、ReactiveWhiteBoard是采取的觀察者設計模式開發的,内部維護了熱信号的數組,是以,請首先保證訂閱者代碼得到執行,否則将不會收到任何資料。
  • 6、資料通訊的完全依賴key值,十分靈活,這就意味着key容易重複,是以可能會帶來各種問題,是以使用前,請確定你key值的唯一性。
  • 7、ReactiveWhiteBoard适用于普通的業務代碼資料通訊,跨子產品,跨元件等;ReactiveBlackBoard适合作為一個複雜對象(例如,可重複壓棧的VC)的屬性變量來使用,複雜的業務類建議自帶了一份ReactiveBlackBoard,便于内部子產品間的資料通訊。

個人公衆号:

iOS開發筆記之七十四——FRP與RAC進階篇(資料黑白闆ReactiveDataBoard的介紹)一、簡介二、接入說明三、實作原理四、補充說明

繼續閱讀