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 之使用
- OC写的ReactiveCocoa框架
- 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