其他分享
首页 > 其他分享> > RAC详解

RAC详解

作者:互联网


各种编程思想汇总

命令式编程

寄存器+运算器(申请内存,计算内存,更注重过程)

//命令式编程举例,求阶乘
int factorialMult(int x) {
    int result = 1;
    for (int i = 1; i <= x; i++) {
        result *= i;
    }
    return result;
}

函数式编程

运算方式,函数(重在表达,更专注的是业务)

//函数式编程举例 n!=n*(n-1)!
int factorialMultTwo(int x){
    if(x == 1) return 1;
    return  x * factorialMultTwo(x-1);
}

函数式编程求最大最小值:

typedef int (^CompareBlock)(int aValue, int aNext);

//函数式编程获取数组中的最大值或者最小值
int maxOrMin(int *array, int count, CompareBlock block) {
    if (count == 1) return array[0];
    int num = maxOrMin(array, count-1, block);
    return block(num, array[count-1]);
}

CompareBlock relative(CompareBlock block) {
    return ^int(int aValue, int aNext){
        return (aValue == block(aValue, aNext) ? aNext:aValue);
    };
}

- (void)viewDidLoad {
    [super viewDidLoad];
    int tests[7] = {5, 4, 1, 3, 6, 8, 7};
    CompareBlock eocBlock = ^int(int aValue, int aNext) {
        return aValue > aNext ? aValue: aNext;
    };
    int max = maxOrMin(tests, 7, eocBlock);
    NSLog(@"max=%d", max);
    int min = maxOrMin(tests, 7, relative(eocBlock));
    NSLog(@"min=%d", min);
}

函数式编程求view在window中的位置:

[_eocButtton originYToWindow:_eocButtton.superview positionY:_eocButtton.frame.origin.y];

@interface UIView (PositionToWindow)
- (CGFloat)originYToWindow:(UIView *)view positionY:(CGFloat)startY;
@end

@implementation UIView (PositionToWindow)
- (CGFloat)originYToWindow:(UIView *)view positionY:(CGFloat)startY {
    if ([view isKindOfClass:[UIWindow class]] || view == nil) {
        return startY;
    } else {
        //自己处理有UIScrollView时的情况
        if ([view.superview isKindOfClass:[UIScrollView class]]) {
            return 0;
        }
    }
    return [self originYToWindow:[view superview] positionY:startY+view.frame.origin.y];
}
@end

响应式编程

响应式的思想,实际是观察者模式,一个值伴随着一个值的变化而变化,更多的是在于种种关联和逻辑关系处理,当一个对象发生变化而产生的关联响应

//响应式编程举例 c值随着a值的变化而变化,如autolayout
void ecoTest(){
    int a = 1;
    int b = 2;
    int c = a+b;
    a = 5;
    printf("%d", c);
}

链式编程

主要通过点‘.’来连接不同的函数调用。iOS上实现链式编程比较好的框架就是Masonry,通过查看Masonry源码,我们发现,每一个函数返回类型都是一个Block变量,然后Block变量中返回的内容就是当前对象本身。

RAC 之使用

  1. OC写的ReactiveCocoa框架
  2. Swift写的RXSwift框架

信号的简单应用

冷信号

订阅就能被触发信号

// 单元信号  冷信号/ 热信号
- (void)signalUnit{
    //1.创建信号
    RACSignal *signalOne = [RACSignal return:@"signalOne"];
    RACSignal *signalTwo = [RACSignal error:[NSError errorWithDomain:@"11.1.11" code:12 userInfo:nil]];
    RACSignal *signalThree = [RACSignal empty];
    RACSignal *signalFour = [RACSignal never];

    //2.订阅
    [signalOne subscribeNext:^(id x) {
        NSLog(@"id:%@", x);
    }];

    [signalTwo subscribeError:^(NSError *error) {
        NSLog(@"signalTwo::%@", error);
    }];

    [signalThree subscribeNext:^(id x) {
        NSLog(@"empty::%@", x);
    }];
}

block信号

// block信号
- (void)racSignalBlock {
    // 1 创建信号
    RACSignal *racSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 3 发送信号
        [subscriber sendNext:@"123456"];
        [subscriber sendNext:@"654321"];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"释放");
        }];
    }];

    // 2 订阅信号
    [racSignal subscribeNext:^(id x) {
        NSLog(@"id:%@", x);
    }];
}

热信号

需要主动触发,可用作通知功能

// 热信号
- (void)hotRacSignal {
    // 1 创建信号
    _hotSubject = [RACSubject subject];
    // 2 订阅信号
    [_hotSubject subscribeNext:^(id x) {
        NSLog(@"One 信号来了:%@", x);
    }];
    // 2 订阅
    [_hotSubject subscribeNext:^(id x) {
        NSLog(@"Tow 信号来了:%@", x);
    }];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if(!_hotSubject) {
        [self hotRacSignal];
    }
    // 3 发送信号
    [_hotSubject sendNext:@"八点钟学院"];
}

监听Button点击事件

- (void)buttonRACHandle {
    RACSignal *touchButtonSignal = [_eocButtton rac_signalForControlEvents:UIControlEventTouchUpInside];
    [touchButtonSignal subscribeNext:^(id x) {
        NSLog(@"点击了");
    } error:^(NSError *error) {
        NSLog(@"error:%@", error);;
    } completed:^{
        NSLog(@"completed");
    }];
}

触发修改Button属性

- (void)buttonUsingSignal {
    RACSignal *textColorSignal = [RACSignal return:[UIColor redColor]];
    RACSignal *statusSignal = [RACSignal return:@(UIControlStateNormal)];
    [_button rac_liftSelector:@selector(setTitleColor:forState:) withSignals:textColorSignal,statusSignal, nil];
}

监听实例方法的触发

@interface EOCObject : NSObject
- (void)eocMethod:(NSString *)eocName;
@end

@implementation EOCObject
- (void)eocMethod:(NSString *)eocName {
    NSLog(@"eocMethod excute %@", eocName);
}
@end

- (void)eocObjectMethodRac {
    _eocObject = [EOCObject new];
    RACSignal *signal = [_eocObject rac_signalForSelector:@selector(eocMethod:)];
    [signal subscribeNext:^(id x) {
        NSLog(@"方法触发了:%@", x);
    }];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (!_eocObject) {
        [self eocObjectMethodRac];
    }
    [_eocObject eocMethod:@"123456"];
}

信号量变换

// 变换
- (void)changeSignal{
    RACSignal *signalOne = [RACSignal return:@"12345678"];
    RACSignal *signalTwo = [signalOne map:^id(id value) {
        NSLog(@"做其他事情");
        return [value substringFromIndex:2];
    }];
    [signalTwo subscribeNext:^(id x) {
        NSLog(@"signalTwo::%@", x);
    }];
}

数组序列化信号的转化与过滤

// 数组
- (void)sequenceRAC {
    RACSignal *signal = @[@"111", @"222", @"3333333", @"44", @"55555"].rac_sequence.signal;
    RACSignal *newSignal = [signal filter:^BOOL(NSString *value) {
        if (value.length>3) {
            return YES;
        } else {
            return NO;
        }
    }];
    [newSignal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
}

信号合并

// 信号组合,多信号处理
- (void)racMerge {
    RACSignal *signalOne = [RACSignal return:@"123"];
    RACSignal *signalTwo = [RACSignal return:@"678"];
    RACSignal *mergeSignal = [signalOne merge:signalTwo];
    [mergeSignal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
}

用信号来对属性监听

- (void)racKVO{
    [RACObserve(self, eocName) subscribeNext:^(id x) {
        NSLog(@"监听属性,触发了");
    }];
    self.eocName = @"八点钟学院";
}

信号量处理线程执行

// 异步操作 (GCD -- )
- (void)racSchedule {
    // 主线程的Scheduler
    RACScheduler *mainScheduler = [RACScheduler mainThreadScheduler];
    // 子线程上的
    RACScheduler *schedulerOne = [RACScheduler scheduler];
    RACScheduler *schedulerTwo = [RACScheduler scheduler];
    // 当前线程的Scheduler, 如果自定义线程会返回一个nil
    RACScheduler *schedulerCurrent = [RACScheduler currentScheduler];

    RACSignal *signalOne = [RACSignal return:@"123"];
    RACSignal *scheduleSignal = [signalOne subscribeOn:schedulerOne];
    [scheduleSignal subscribeNext:^(id x) {
        NSLog(@"%@", [NSThread currentThread]);
    }];
}

用信号量延时执行

/// 延时
- (void)delayRac {
    RACScheduler *mainScheduler = [RACScheduler currentScheduler];
    [mainScheduler afterDelay:2 schedule:^{
        NSLog(@"afterDelay");
    }];
}

RAC 之源码分析

signal生成

//生成一个signal,信号变量中保存初始化时的信息
//如果是return signal,保存value
//如果是error signal,保存error
//如果是block signal,保存block
RACSignal *signalOne = [RACSignal return:@"signalOne"];
RACSignal *signalTwo = [RACSignal error:[NSError errorWithDomain:@"11.1.11" code:12 userInfo:nil]];
RACSignal *racSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"subscriber block");
    [subscriber sendNext:@"123456"];
    return nil;
}];

//RACSignal
+ (RACSignal *)return:(id)value {
    return [RACReturnSignal return:value];
}

+ (RACSignal *)error:(NSError *)error {
    return [RACErrorSignal error:error];
}

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}

//RACReturnSignal
+ (RACSignal *)return:(id)value {
#ifndef DEBUG
    // In release builds, use singletons for two very common cases.
    if (value == RACUnit.defaultUnit) {
        static RACReturnSignal *unitSingleton;
        static dispatch_once_t unitPred;

        dispatch_once(&unitPred, ^{
            unitSingleton = [[self alloc] init];
            unitSingleton->_value = RACUnit.d 大专栏  RAC详解efaultUnit;
        });

        return unitSingleton;
    } else if (value == nil) {
        static RACReturnSignal *nilSingleton;
        static dispatch_once_t nilPred;

        dispatch_once(&nilPred, ^{
            nilSingleton = [[self alloc] init];
            nilSingleton->_value = nil;
        });

        return nilSingleton;
    }
#endif

    RACReturnSignal *signal = [[self alloc] init];
    signal->_value = value;

#ifdef DEBUG
    [signal setNameWithFormat:@"+return: %@", value];
#endif

    return signal;
}

//RACErrorSignal
+ (RACSignal *)error:(NSError *)error {
    RACErrorSignal *signal = [[self alloc] init];
    signal->_error = error;

#ifdef DEBUG
    [signal setNameWithFormat:@"+error: %@", error];
#else
    signal.name = @"+error:";
#endif

    return signal;
}

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

signal订阅

//订阅signal,通过源码可以看出,returnSignal和errorSignal在订阅时就会触发执行block,而通过块生成的RACDynamicSignal订阅时并不会执行block,需要通过块中的subscribe去手动send
[racSignal subscribeNext/Error:^(id x) {
    NSLog(@"subscriber next id:%@", x);
}];

//RACSignal,根据nextBlock,errorBlock,completeBlock封装一个RACSubscriber对象
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);

    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

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

    return [RACScheduler.subscriptionScheduler schedule:^{
        [subscriber sendNext:self.value];
        [subscriber sendCompleted];
    }];
}

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

    return [RACScheduler.subscriptionScheduler schedule:^{
        [subscriber sendError:self.error];
    }];
}

//RACDynamicSignal
- (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;
}

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

        nextBlock(value);
    }
}

- (void)sendError:(NSError *)e {
    @synchronized (self) {
        void (^errorBlock)(NSError *) = [self.error copy];
        [self.disposable dispose];

        if (errorBlock == nil) return;
        errorBlock(e);
    }
}

- (void)sendCompleted {
    @synchronized (self) {
        void (^completedBlock)(void) = [self.completed copy];
        [self.disposable dispose];

        if (completedBlock == nil) return;
        completedBlock();
    }
}

热信号

通过源码可看出,热信号并没有在订阅的时候执行,而是要专门调用sendNext,而冷信号在订阅的时候就已经执行了,所以冷信号不需要sendNext也没有此功能,只需要订阅就好了

- (void)hotRacSignal {
    // 1 创建信号
    _hotSubject = [RACSubject subject];
    // 2 订阅信号
    [_hotSubject subscribeNext:^(id x) {
        NSLog(@"One 信号来了:%@", x);
    }];
    // 3 订阅
    [_hotSubject subscribeNext:^(id x) {
        NSLog(@"Tow 信号来了:%@", x);
    }];
    [_hotSubject sendNext:@"八点钟学院"];
}

@interface RACSubject : RACSignal <RACSubscriber>
+ (instancetype)subject;
@end

@protocol RACSubscriber <NSObject>
- (void)sendNext:(id)value;
- (void)sendError:(NSError *)error;
- (void)sendCompleted;
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
@end

//RACSubject
+ (instancetype)subject {
    return [[self alloc] init];
}

- (id)init {
    self = [super init];
    if (self == nil) return nil;

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

    return self;
}

//RACSignal
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);

    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

//RACSubject
- (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];
    }

    return [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];
        }
    }];
}

举例:

改变button字体颜色

- (void)buttonUsingSignal {
    RACSignal *textColorSignal = [RACSignal return:[UIColor redColor]];
    RACSignal *statusSignal = [RACSignal return:@(UIControlStateNormal)];
    [_button rac_liftSelector:@selector(setTitleColor:forState:) withSignals:textColorSignal,statusSignal, nil];
}

//NSObject+RACLifting
- (RACSignal *)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... {
    NSCParameterAssert(firstSignal != nil);

    NSMutableArray *signals = [NSMutableArray array];

    va_list args;
    va_start(args, firstSignal);
    for (id currentSignal = firstSignal; currentSignal != nil; currentSignal = va_arg(args, id)) {
        NSCAssert([currentSignal isKindOfClass:RACSignal.class], @"Argument %@ is not a RACSignal", currentSignal);

        [signals addObject:currentSignal];
    }
    va_end(args);

    return [[self
        rac_liftSelector:selector withSignalsFromArray:signals]
        setNameWithFormat:@"%@ -rac_liftSelector: %s withSignals: %@", self.rac_description, sel_getName(selector), signals];
}
- (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals {
    NSCParameterAssert(signals != nil);
    NSCParameterAssert(signals.count > 0);

    NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
    NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector));

    NSUInteger numberOfArguments __attribute__((unused)) = methodSignature.numberOfArguments - 2;
    NSCAssert(numberOfArguments == signals.count, @"Wrong number of signals for %@ (expected %lu, got %lu)", NSStringFromSelector(selector), (unsigned long)numberOfArguments, (unsigned long)signals.count);

    return [[self
        rac_liftSelector:selector withSignalOfArguments:[RACSignal combineLatest:signals]]
        setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsFromArray: %@", self.rac_description, sel_getName(selector), signals];
}

- (RACSignal *)rac_liftSelector:(SEL)selector withSignalOfArguments:(RACSignal *)arguments {
    NSCParameterAssert(selector != NULL);
    NSCParameterAssert(arguments != nil);

    @unsafeify(self);

    NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
    NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector));

    return [[[[arguments
        takeUntil:self.rac_willDeallocSignal]
        map:^(RACTuple *arguments) {
            @strongify(self);

            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
            invocation.selector = selector;
            invocation.rac_argumentsTuple = arguments;
            [invocation invokeWithTarget:self];

            return invocation.rac_returnValue;
        }]
        replayLast]
        setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsOfArguments: %@", self.rac_description, sel_getName(selector), arguments];
}

//NSInvocation+RACTypeParsing
- (void)setRac_argumentsTuple:(RACTuple *)arguments {
    NSCAssert(arguments.count == self.methodSignature.numberOfArguments - 2, @"Number of supplied arguments (%lu), does not match the number expected by the signature (%lu)", (unsigned long)arguments.count, (unsigned long)self.methodSignature.numberOfArguments - 2);

    NSUInteger index = 2;
    for (id arg in arguments) {
        [self rac_setArgument:(arg == RACTupleNil.tupleNil ? nil : arg) atIndex:index];
        index++;
    }
}

监听button的点击信号

RACSignal *signalTwo =  [button rac_signalForControlEvents:UIControlEventTouchUpInside];
[signalTwo subscribeNext:^(id x) {
    // button响应了点击事件, 订阅者可以做事情了
    NSLog(@"signalTwo::%@", x);
}];

//UIControl+RACSignalSupport
- (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents {
    @weakify(self);

    return [[RACSignal
        createSignal:^(id<RACSubscriber> subscriber) {
            @strongify(self);

            [self addTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
            [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
                [subscriber sendCompleted];
            }]];

            return [RACDisposable disposableWithBlock:^{
                @strongify(self);
                [self removeTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
            }];
        }]
        setNameWithFormat:@"%@ -rac_signalForControlEvents: %lx", self.rac_description, (unsigned long)controlEvents];
}

更改view的background

#define RAC_(TARGET, KEYPATH, NILVALUE)  [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)]

RACSignal *viewColorSignal = [RACSignal return:[UIColor blueColor]];
RAC(self.view, backgroundColor) = viewColorSignal;

//上句可以翻译成下面这句
RACSubscriptingAssignmentTrampoline *tmp =  [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(self.view) nilValue:nil];
tmp[@"backgroundColor"] = viewColorSignal;

//因为RACSubscriptingAssignmentTrampoline类实现了以下方法,所以可以根据key直接赋值tmp[@"backgroundColor"] = viewColorSignal;
- (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath;
//如果需要也根据key取值,可以实现此方法
- (id)objectForKeyedSubscript:(NSString*)key;

标签:return,RAC,self,RACSignal,subscriber,详解,void,id
来源: https://www.cnblogs.com/liuzhongrong/p/12251110.html