ReactiveCocoa学习之RACSubject

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)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 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 subscriber) {
     [subscriber sendNext:value];
     }];
     }
     
     - (void)enumerateSubscribersUsingBlock:(void (^)(id subscriber))block {
     NSArray *subscribers;
     @synchronized (self.subscribers) {
     subscribers = [self.subscribers copy];
     }
     
     for (id 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 *)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)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)