ios RAC使用總結(jié)(RACSignal、RACDisposable、RACSubject)

在開始MVVM之前,RAC是肯定繞不過去的。MVVM+RAC真的是雙劍合璧。今天 我們先來看看RAC的使用和一些原理實現(xiàn),然后再結(jié)合項目中的登錄來實踐一下。

RACSignal

先從最簡單的RACSignal開始,我們先來看看它是怎么創(chuàng)建的。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    [self creatSigal];
}

-(void)creatSigal{
    
    RACSignal *sigal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@"你個小樣"];
        
        return nil;
    }];
    
    [sigal subscribeNext:^(id  _Nullable x) {
       
        NSLog(@"傳遞的數(shù)據(jù)是:----%@",x);
    }];
    
}

輸出打印的是:LBDaySurgery(Dev)[10211:3806511] 傳遞的數(shù)據(jù)是:----你個小樣

上面就創(chuàng)建了一個信號,并且訂閱信號,還發(fā)送消息了。創(chuàng)建是成功了,但是它具體的原來還不知道啊。不要慌,我們點進(jìn)方法看看。

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}

創(chuàng)建信號的方法是這么個東西。首先RACDynamicSignal這是個什么,然后再點發(fā)現(xiàn)

@interface RACDynamicSignal : RACSignal

它其實就是一個信號,先初始化了RACDynamicSignal,然后下面_didSubscribe這個熟悉嘛,是不是有點像訂閱信號,RACDynamicSignal持有了didSubscribe,最后返回了一個信號。這個方法看完了,有一個疑問,didSubscribe這個是用來干嘛的?接著往下看
訂閱信號的方法

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

第一行很容易理解,就是創(chuàng)建RACSubscriber(訂閱者),點進(jìn)去看看它里面的實現(xiàn)

+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
    RACSubscriber *subscriber = [[self alloc] init];

    subscriber->_next = [![邏輯圖.png](https://upload-images.jianshu.io/upload_images/9788931-865189b71e7896ea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
 copy];
    subscriber->_error = [error copy];
    subscriber->_completed = [completed copy];

    return subscriber;
}

我們發(fā)現(xiàn),它初始化了訂閱者,然后訂閱者持有了next這個block,持有了error、completed,很簡單。點進(jìn)去看[self subscribe:o];的實現(xiàn)

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
//看的有點懵,上面的對象都不知道是什么 但是didSubscribe這個熟悉啊,在創(chuàng)建信號的時候RACDynamicSignal持有didSubscribe
    if (self.didSubscribe != NULL) {
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
//這里調(diào)用didSubscribe方法,并且把剛才傳入的subscriber調(diào)用出去
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            [disposable addDisposable:innerDisposable];
        }];

        [disposable addDisposable:schedulingDisposable];
    }
    
    return disposable;
}

現(xiàn)在我們最開始的疑問解開了,didSubscribe的調(diào)用。這個方法里能看懂的就是,先判斷有沒有didSubscribe,有的話就執(zhí)行這個方法,參數(shù)是subscriber訂閱者。后面我們在說RACDisposable。

- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;

        nextBlock(value);
    }
}

上面是訂閱者發(fā)送消息的方法實現(xiàn),判斷有沒有nextblock,而這里的nextblock也正是subscriber->_next = [next copy];保存的。如果有 就把發(fā)送的消息,傳遞出去。
上面我們一個一個的都點進(jìn)去看了他們的具體實現(xiàn),現(xiàn)在來張圖更加直觀的看看這個過程


邏輯圖.png

這里面有要說明的是:didSubscribe的參數(shù)是RACSubscriber,而在我們發(fā)送消息的時候, [subscriber sendNext:@"你個小樣"]; 這里的訂閱者就是didSubscribe傳入的,而訂閱者持有nextblock,所以nextBlock(value);消息就傳入到訂閱的block中了。這就是創(chuàng)建RACSignal的一個流程。

RACDisposable

在上面創(chuàng)建信號的時候,返回了空,但是我們點進(jìn)方法里面,它應(yīng)該返回一個RACDisposable。
1.什么是RACDisposable

RACDisposable:用于取消訂閱或者清理資源,當(dāng)信號銷毀或者發(fā)送錯誤的時候,就會自動觸發(fā)。
使用場景:不想監(jiān)聽某個信號時,可以通過它主動取消訂閱信號
我們來看看它的使用:

-(void)creatSigal{
    
    RACSignal *sigal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"創(chuàng)建成功");
        [subscriber sendNext:@"你個小樣"];
        NSLog(@"發(fā)送消息之后");
        
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"這是什么什么時候調(diào)用");
        }];
    }];
    [sigal subscribeNext:^(id  _Nullable x) {
        NSLog(@"傳遞的數(shù)據(jù)是:----%@",x);
    }];
    
}
打印出:2021-04-08 14:08:52.687740+0800 LBDaySurgery(Dev)[10407:3878985] 創(chuàng)建成功
2021-04-08 14:08:52.687781+0800 LBDaySurgery(Dev)[10407:3878985] 傳遞的數(shù)據(jù)是:----你個小樣
2021-04-08 14:08:52.687795+0800 LBDaySurgery(Dev)[10407:3878985] 發(fā)送消息之后
2021-04-08 14:08:52.687819+0800 LBDaySurgery(Dev)[10407:3878985] 這是什么什么時候調(diào)用

我們發(fā)現(xiàn)信號被銷毀以后,就就會調(diào)用。
另外我們還可以主動調(diào)用 也會銷毀

 RACDisposable *disposable=[sigal subscribeNext:^(id  _Nullable x) {
        NSLog(@"傳遞的數(shù)據(jù)是:----%@",x);
    }];
    [disposable dispose];
RACSubject

創(chuàng)建信號當(dāng)然不是一種方法,還有其他的方法。先上代碼

-(void)creatracSubject{
    
    RACSubject *subject=[RACSubject subject];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"收到的消息是:---%@",x);
    }];
    //發(fā)送消息
    [subject sendNext:@"666 666"];
    
}
 LBDaySurgery(Dev)[10505:3899054] 收到的消息是:---666 666

我們點進(jìn)方法看看它的實現(xiàn)原理

+ (instancetype)subject {
    return [[self alloc] init];
}
- (instancetype)init {
    self = [super init];
    if (self == nil) return nil;

    _disposable = [RACCompoundDisposable compoundDisposable];
    _subscribers = [[NSMutableArray alloc] initWithCapacity:1];
    
    return self;
}

創(chuàng)建subject對象時,初始化了一個取消信號和一個數(shù)組,從名字我們能看出這是用來存放訂閱者的。
接著看訂閱信號的實現(xiàn)

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

好熟悉,和RACSignal一毛一樣,但是里面里面的實現(xiàn)就不同了,而且他兩也不是同一個類。創(chuàng)建RACSubscriber *o 這個是一樣的我們不需要看,主要是下面的[self subscribe:o];

- (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];
    }
    
    [disposable addDisposable:[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];
        }
    }]];

    return disposable;
}

從上面這段代碼能看到,是把訂閱者都加入到subscribers數(shù)組中了。

我們再看發(fā)布消息的實現(xiàn)

- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
    NSArray *subscribers;
    @synchronized (self.subscribers) {
        subscribers = [self.subscribers copy];
    }
//遍歷subscribers中的訂閱者,然后block傳遞subscriber
    for (id<RACSubscriber> subscriber in subscribers) {
        block(subscriber);
    }
}

#pragma mark RACSubscriber

- (void)sendNext:(id)value {
    [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
//這里和之前RACSignal發(fā)送消息相同
        [subscriber sendNext:value];
    }];
}

1.創(chuàng)建的subject內(nèi)部會創(chuàng)建數(shù)組_subscribers,用來保存所有的訂閱者。
2.訂閱信息的時候會創(chuàng)建訂閱者
3.發(fā)送消息的時候,會依次發(fā)送。

-(void)creatracSubject{
    
    RACSubject *subject=[RACSubject subject];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"收到的消息是:---%@",x);
    }];
    //發(fā)送消息
    [subject sendNext:@"666 666"];
    
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"第二次收到:--%@",x);
    }];
    
    [subject sendNext:@"888888"];
    
}

上面這個會打印出什么呢?在第一次發(fā)送消息的時候[subject sendNext:@"666 666"];,會打印出666,當(dāng)調(diào)用到[subject sendNext:@"888888"];,因為subject可以多次訂閱,所以不僅第二次會打印,第一次同樣也會打印出。所以最后打印出

2021-04-08 15:38:37.497503+0800 LBDaySurgery(Dev)[10525:3913448] 收到的消息是:---666 666
2021-04-08 15:38:37.497542+0800 LBDaySurgery(Dev)[10525:3913448] 收到的消息是:---888888
2021-04-08 15:38:37.497555+0800 LBDaySurgery(Dev)[10525:3913448] 第二次收到:--888888

我們再看下面這段代碼

-(void)creatracSubject{
    
    RACSubject *subject=[RACSubject subject];
    [subject sendNext:@"888888"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"收到的消息是:---%@",x);
    }];
    
}

一運行發(fā)現(xiàn)沒打印出來,這是為什么呢?這是因為在發(fā)送消息是要遍歷存放訂閱者的數(shù)組,但是這個數(shù)組現(xiàn)在是空的,它只有在訂閱消息的時候才會加入到數(shù)組,自然就不會發(fā)送消息,也就不會打印出結(jié)果。
如果非要把順序?qū)懗上劝l(fā)送消息 在訂閱,那么我們可以用RACReplaySubject來實現(xiàn)

-(void)creatReplaySubject{
    
    RACReplaySubject *subject=[RACReplaySubject subject];
    [subject sendNext:@"888888"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"收到的消息是:---%@",x);
    }];
    
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容