美文网首页
ReactiveCocoa学习之RACSubject

ReactiveCocoa学习之RACSubject

作者: 最晴天 | 来源:发表于2018-05-31 18:10 被阅读20次

    RACSubject的底层实现和RASReplaySubject的底层实现,与RACSignal一样吗?

    RACSubscriber 订阅者

    用于发送信号,这是一个协议。
    RACSubscriber协议有4个必须实现的方法:
    - (void)sendNext:(nullable id)value;
    - (void)sendError:(nullable NSError *)error;
    - (void)sendCompleted;
    - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;

    RACDisposable:用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。

    RACSubject

    是RACSignal的子类,因此可以充当信号,但同时它还能发送信号

    使用步骤类似与RACSignal:
    1.创建信号 [RACSubject subject]
    2.订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
    3.发送信号 sendNext:(id)value
    但它的底层实现与RACSignal不一样。

    究竟怎么不一样呢?
    1. subject创建时,在创建RACCompoundDisposable的同时,还创建了一个订阅者数组。
    2. subscribeNext调用时,除了创建订阅者,及 将nextBlock保存起来,同时会将创建的订阅者添加到订阅者数组中。
    3. sendNext 发送信号,会遍历subject所有的订阅者,并依次调用订阅者的nextBlock
     RACSubject *subject = [RACSubject subject];
        [subject subscribeNext:^(id  _Nullable x) {
            // block调用时刻:当信号发出新值,就会调用.
            NSLog(@"第一个订阅者%@",x);
        }];
        [subject subscribeNext:^(id  _Nullable x) {
            // block调用时刻:当信号发出新值,就会调用.
            NSLog(@"第二个订阅者%@",x);
        }];
        [subject sendNext:@"1"];
    
       /*
         源码分析
         1.subject创建时,在创建RACCompoundDisposable的同时,还创建了一个订阅者数组。
         - (instancetype)init {
         self = [super init];
         if (self == nil) return nil;
         
         _disposable = [RACCompoundDisposable compoundDisposable];
         _subscribers = [[NSMutableArray alloc] initWithCapacity:1];
         
         return self;
         }
         2.subscribeNext调用时,除了创建订阅者,及 将nextBlock保存起来,同时会将创建的订阅者添加到订阅者数组中。
         
         - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
         NSCParameterAssert(nextBlock != NULL);
         
         RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
         return [self subscribe:o];
         }
         
         
         + (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;
         }
         
         #pragma mark Subscription
         
         - (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;
         }
         
         3.sendNext 发送信号,会遍历subject所有的订阅者,并依次调用订阅者的nextBlock
         
         
         - (void)sendNext:(id)value {
         [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
         [subscriber sendNext:value];
         }];
         }
         
         - (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
         NSArray *subscribers;
         @synchronized (self.subscribers) {
         subscribers = [self.subscribers copy];
         }
         
         for (id<RACSubscriber> subscriber in subscribers) {
         block(subscriber);
         }
         }
         
         
         #pragma mark RACSubscriber
         
         - (void)sendNext:(id)value {
         @synchronized (self) {
         void (^nextBlock)(id) = [self.next copy];
         if (nextBlock == nil) return;
         
         nextBlock(value);
         }
         }
         
         */
    
    

    RACSubject可以用来代替delegate传值,类似于block传值。

    #import "TwoViewController.h"
    
    
    @interface TwoViewController ()
    
    @property (weak, nonatomic) IBOutlet UIButton *backBtn;
    @property (weak, nonatomic) IBOutlet UIImageView *imgV;
    @property (weak, nonatomic) IBOutlet UITextField *accountTF;
    @property (weak, nonatomic) IBOutlet UITextField *passwordTF;
    @property (weak, nonatomic) IBOutlet UIButton *resetBtn;
    
    
    
    
    @end
    
    @implementation TwoViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        
        
        @weakify(self);
        [[self.backBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
            @strongify(self);
            
            [self dismissViewControllerAnimated:YES completion:nil];
        }];
        
        
        RACSignal *signalA = [self.accountTF rac_textSignal];
        RACSignal *signalB = [[self.passwordTF rac_textSignal] filter:^BOOL(NSString * _Nullable value) {
            @strongify(self);
            if (self.passwordTF.text.length > 5) {
                self.passwordTF.text = [self.passwordTF.text substringToIndex:5];
            }
            return value.length < 5;
        }];
        
        [[RACSignal combineLatest:@[signalA, signalB] reduce:^id (NSString *account,NSString *password){
            return @(account.length && password.length);
        }] subscribeNext:^(NSNumber *x) {
            @strongify(self);
            self.resetBtn.enabled = x.integerValue;
        }];
        
        [[self.resetBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
            NSLog(@"%@",x);
            @strongify(self);
            if (self.delegateSubject) {
                [self.delegateSubject sendNext:@[self.accountTF.text, self.passwordTF.text]];
            }
            
            [self dismissViewControllerAnimated:YES completion:nil];
        }];
        
       
        
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        [self.view endEditing:YES];
    }
    
    
    在第一个ViewController中
    
     @weakify(self);
        [[self.otherBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
            @strongify(self);
            TwoViewController *twoVC = [TwoViewController new];
            //设置代理信号
            twoVC.delegateSubject = [RACSubject subject];
            [twoVC.delegateSubject subscribeNext:^(id  _Nullable x) {
                
            }];
            [twoVC.delegateSubject subscribeNext:^(NSArray *x) {
                NSLog(@"点击了通知按钮");
               @strongify(self);
                self.accountTF.text = x[0];
                self.passwordTF.text = x[1];
                
            }];
            [self presentViewController:twoVC animated:YES completion:nil];
        }];
    
        
    

    RACReplaySubject

    是RACSubject的子类,但它可以先订阅信号,也可以先发送信号。

    如果 一个信号被订阅,就会重复播放之前的所有值,那就要先发送信号,再订阅信号。

    它的底层实现又不同于父类RACSubject。???
    1. 创建信号,与RACSubject一样
    2. sendNext发送信号,不同于RACSubject.会将发送的信号添加到值接收的数组中去,然后再遍历所有的订阅者,依次调用订阅者的nextBlock
    3. subscribeNex订阅信号时,除创建订阅者,保存nextBlock,将订阅者添加到订阅者数组中去 这些操作之外,还会遍历replaySubject的valuesReceived数组(该数组中保存的是发送的信号值),依次将这些值再发送一次
     // 1.创建信号
        RACReplaySubject *replaySubject = [RACReplaySubject subject];
        
        // 2.发送信号
        [replaySubject sendNext:@1];
        [replaySubject sendNext:@2];
        
        // 3.订阅信号
        [replaySubject subscribeNext:^(id x) {
            
            NSLog(@"第一个订阅者接收到的数据%@",x);
        }];
        
        // 订阅信号
        [replaySubject subscribeNext:^(id x) {
            
            NSLog(@"第二个订阅者接收到的数据%@",x);
        }];
    
    
     /*
         底层分析:
         1.创建信号,与RACSubject一样
         2.sendNext发送信号,不同于RACSubject.会将发送的信号添加到值接收的数组中去,然后再遍历所有的订阅者,依次调用订阅者的nextBlock
         
         - (void)sendNext:(id)value {
         @synchronized (self) {
         [self.valuesReceived addObject:value ?: RACTupleNil.tupleNil];
         [super sendNext:value];
         
         if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
         [self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
         }
         }
         }
         
         3.subscribeNex订阅信号时,除创建订阅者,保存nextBlock,将订阅者添加到订阅者数组中去 这些操作之外,还会遍历replaySubject的valuesReceived数组(该数组中保存的是发送的信号值),依次将这些值再发送一次
         
         
         - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
         NSCParameterAssert(nextBlock != NULL);
         
         RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
         return [self subscribe:o];
         }
         
         
         + (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;
         }
         
         #pragma mark RACSignal
         
         - (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;
         
         [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 {
         RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
         [compoundDisposable addDisposable:subscriptionDisposable];
         }
         }
         }];
         
         [compoundDisposable addDisposable:schedulingDisposable];
         
         return compoundDisposable;
         }
         
         */
    
    

    相关文章

      网友评论

          本文标题:ReactiveCocoa学习之RACSubject

          本文链接:https://www.haomeiwen.com/subject/wiuqsftx.html