美文网首页
iOS:RAC之RacSignal

iOS:RAC之RacSignal

作者: ForC | 来源:发表于2017-12-10 20:51 被阅读142次

理解

RAC框架很强大,之前使用的mvc都是通过赋值然后实现页面的刷新,mvc架构对controller层比较重,复用的地方比较多的情况下,复杂界面很难直接拿过去用,依稀记得之前写了一个业务代码一个页面将近20种类状态,表现了20多种类的显示。当时实在写的自己都很烦,后来做了一下review,将控制器的代码分成了api层,manager层,C中减少了大部分代码,后来看了一下对于mvvm的介绍吧,其中个人认为vm的存在就是替代了我之前的manger,将部分东西都放这个在了vm中,vm重要也代替了部分api的操作。如果网络层封装不错的情况下,可以替代掉api吧。mvvm框架的引入导致代码中代理啊,block,通知之类的传值很混乱。所以有了rac,这个框架引入后完美的结合了你的c的vm,部分v层的vm可以通用,这样就有了多页面传值功效。(个人理解)

使用

cocoapod倒入podFile写上pod 'ReactiveCocoa', '~> 2.5'就可以了。(注:3.0.0以上的rac框架支持swift如果纯oc项目建议使用3.0.0以下)

个人感悟

第一次接触rac妄自菲薄以为自己几天可以完全学会吧,但是看了几个项目看了看源码觉得这个是在妄想,当时公司在扩展业务所以拿了一个端做了rac框架(如果是针对业务层几天基本足够了,但是出现部分问题得学一些其他的基础)

RacSignal

RacSignal:信号类,基础类所有信号几本都继承RacSignal,但信号类实例化不支持发送,只是传递的媒介,所以需要RacSignal常用的三部曲

  • 创建信号
  • 订阅信号
  • 发送信号

1.创建信号

RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

         RACDisposable *dispoable = [RACDisposable disposableWithBlock:^{
            NSLog(@"dispoable");
        }];
    
        return dispoable;
    }];

2.订阅信号

RACDisposable *autoDisposable = [signal subscribeNext:^(id  _Nullable x) {
        // 接收
        NSLog(@"%@", x);
    }];
    //销毁
    [autoDisposable dispose];
    

3.发送信号

  [subscriber sendNext:@"string"];

源码阅读

  • 创建信号
    很简单的一个信号传递过程就这么结束了,业务代码也就这样就够了,但是好奇的我点了进去看了看代码。从创建开始看,
    RACSignal类里createSignal方法返回了RACDynamicSignal实例
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}

进一步看只是RACDynamicSignal有了实例化并将发送信号的block传给了_didSubscribe只读属性

RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];

接着setNameWithFormat方法来创建一个基础的createSignal流名字, va_list是c中用来多入参的操作的,基本就是多入参拼接string得到一个参数如下含义一致。然后name根据官方api就是一个信号流的名字主要用于调试

    NSString *str = @"121";
    NSString *str1 = [NSString stringWithFormat:@"121%@", str];
- (instancetype)setNameWithFormat:(NSString *)format, ... {
    if (getenv("RAC_DEBUG_SIGNAL_NAMES") == NULL) return self;

    NSCParameterAssert(format != nil);

    va_list args;
    va_start(args, format);

    NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);

    self.name = str;
    return self;
}

到这里创建信号基本就完事掉了。

  • 订阅信号
    订阅的过程相对麻烦一些,创建一个订阅者并传入操作block,
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

//信号加入订阅(这里为什么跳转这个方法自己考虑下),销毁其它关于销毁机制的后边会说
- (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;
}

  • 发送信号
    发送的过程就是一个回掉加了个锁的处理。
- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;

        nextBlock(value);
    }
}
注:这里说一下rac的销毁机制,我看了一下源码主要
调用的地方
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
//rac中订阅者的传递是针对于RACPassthroughSubscriber类来传递,其中包含了信号,订阅者销毁实例类
    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;
}
//rac的RACCompoundDisposable中最多产生两个销毁回掉对象,一个是订阅以后产生的,一个是创建以后产生的,其中一个更新,相对也会更新_inlineDisposables数组
- (void)addDisposable:(RACDisposable *)disposable {
    NSCParameterAssert(disposable != self);
    if (disposable == nil || disposable.disposed) return;

    BOOL shouldDispose = NO;

    OSSpinLockLock(&_spinLock);
    {
        if (_disposed) {
            shouldDispose = YES;
        } else {
            #if RACCompoundDisposableInlineCount
//只走了这里
            for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
                if (_inlineDisposables[i] == nil) {
                    _inlineDisposables[i] = disposable;
                    goto foundSlot;
                }
            }
            #endif

            if (_disposables == NULL) _disposables = RACCreateDisposablesArray();
            CFArrayAppendValue(_disposables, (__bridge void *)disposable);

            if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) {
                RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
            }

        #if RACCompoundDisposableInlineCount
        foundSlot:;
        #endif
        }
    }
    OSSpinLockUnlock(&_spinLock);

    // Performed outside of the lock in case the compound disposable is used
    // recursively.
    if (shouldDispose) [disposable dispose];
}

总结

signal中一个didsubcriber的属性,这个blcok的参数有一个订阅者,这个订阅者也是一个block。如图

1940927-ab788da327c2842c.jpg

注:图片引用:http://www.jianshu.com/p/35a28cf0a22f

最后的最后

rac的传递表面是是很乱的,其中包含了最少3个block进行传递,其实自己仔细画图理解一下就明白了其中的
我模仿了这种信号传递方式写了伪代码,方便学习的人理解希望对有需要的人提供帮助。git:https://github.com/Heqiao1025/RACSignalDemo

相关文章

  • (一)、iOS RAC - RACSignal

    (一)、iOS RAC - RACSignal (二)、iOS RAC - RACDisposable(三...

  • iOS:RAC之RacSignal

    理解 RAC框架很强大,之前使用的mvc都是通过赋值然后实现页面的刷新,mvc架构对controller层比较重,...

  • iOS RAC - RACSignal

    文章系列《RACSignal 》《RACDisposable》《RACSubject、RACReplaySubje...

  • RACSignal介绍

    RACSignal 在RAC中最核心的类RACSignal,搞定这个类就能用ReactiveCocoa了。 RAC...

  • iOS: RAC篇 - RACSignal

    对于最近公司一个项目涉及到了RAC, 再结合着网上其他大佬的文章做一下整理.RAC的简介就不做介绍了, 百度会不会...

  • RAC的基本使用

    RAC的基本使用 在RAC中,一切都是信号! RACSignal RACSignal实例化一个信号,首先,需要创建...

  • RAC 组合combine

    RAC(_btn,enabled) = [RACSignal combineLatest:@[_accountTe...

  • iOS RAC学习之路1之RACSignal

    学习准备 其实很早之前了解RAC并有意学习,只是没有时间写下来,对于一个开发者RAC确实妙不可言,但是也不要盲目的...

  • iOS开发 「RAC」用RAC实现界面有多个请求都完成后再刷新界

    - (RACSignal *)rac_liftSelector:(SEL)selector withSignals...

  • RAC - RACSignal

    信号类,一般表示将来有数据传递,只要有数据改变,信号内部接收到数据们就会马上发出数据。 信号类,只是表示当前数据改...

网友评论

      本文标题:iOS:RAC之RacSignal

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