iOS RAC系列
①、iOS-RAC的开发用法-底层分析以及总结
②、iOS-RAC-核心类分析-RACPassthroughSubscriber订阅者-RACScheduler调度者-RACDisposable销毁者-RACObseve监听者-RACSubject
③、iOS-RAC-底层分析-RAC的宏-RACCommand
(完)④、iOS-RAC-在实际开发的使用-以登录注册为例子
Demo
Demo-iOS-RAC-高阶函数-带注释
iOS-RAC-实际开发案例-登录注册
资料
iOS-RAC底层源码分析-思维导图-MindNote
iOS-RAC的宏-RACCommand
- ①、RAC的宏
- ②、RACCommand
- 1.RACCommand的使用 `executionSignals 执行信号`、`switchToLatest 最新`、`errors 错误`、`executing 执行`
- 2.RACCommand底层逻辑分析
- 2.1我们先看一下`RACCommand`的初始化方法
- 2.2我们先看一下`RACCommand`的`initWithSignalBlock`、`initWithEnabled:signalBlock`
- 我们看到 RACCommand `initWithEnabled:signalBlock`有很多属性 是用来状态 判断是否 正在来、是否在执行、是否发生错误
- 我们最重要的核心就是看`addedExecutionSignalsSubject`,他是属于`RACSubject`.`RACSubject`是即可攻也可以守的。
- 2.3 `addedExecutionSignalsSubject` 有了`signal`信号 `subscribeNext`订阅才有用
①、RAC的宏
1.RAC的宏 @weakify
拆分
// 宏定义
- (void)Define
{
// 宏:
// # 宏参数 答题参数值为内容的字符常量
// A##B ----> AB
// .... 参数 ---- __VA_ARGS -- LOG
// 封装流程 ---- 装逼
@weakify(self);
// 用宏封装了这么多层 更多是面向用户开发者
// @weakify 最终生成的是 __weak __typeof__(self) self_weak_ = (self);
/**
1、@weakify =
#define weakify(...) \
rac_keywordify \
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
2、rac_keywordify = autoreleasepool {}
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
3、得到 autoreleasepool {
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
}
4、metamacro_foreach_cxt = #define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
5、#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
将数据代入
MACRO = rac_weakify_
SEP =
CONTEXT = __weak
6、#define metamacro_foreach_cxt(rac_weakify_, , __weak, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
7、metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))
==
#define metamacro_concat(A, B) \
metamacro_concat_(A, B)
// metamacro_argcount 什么意思 : argcount 参数个数
8、metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))
metamacro_argcount(__VA_ARGS__) == #define metamacro_argcount(...) \
metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
9、 metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) =
#define metamacro_at(N, ...) \
metamacro_concat(metamacro_at, N)(__VA_ARGS__)
10、metamacro_at20(__VA_ARGS__) === #define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, self.name) metamacro_head(__VA_ARGS__)
11、 #define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, 20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) metamacro_head(__VA_ARGS__)
self.name = metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
12、metamacro_head === #define metamacro_head_(FIRST, ...) FIRST
//只接受前面的1个值
13、 metamacro_at20 只能填充20个 所以这里只能从前面一直数 数到20个 self.name = metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
剩下 2跟1
16、
//得出 metamacro_foreach_cxt2
metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, __VA_ARGS__)
#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
SEP \
MACRO(1, CONTEXT, _1)
// 最终 变成了 #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0)
// SEP是空
rac_weakify_(1,__weak,_1)
// #define rac_weakify_(INDEX, CONTEXT, VAR) \
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
// VAR 就是传过来的 self
__weak __typeof__(self) self_weak_ = (self);
*/
}
②、RACCommand
1.RACCommand的使用 executionSignals 执行信号
、switchToLatest 最新
、errors 错误
、executing 执行
// RACCommand
- (void)RACCommand
{
// RACCommand 是个 object
// 用来监听 状态 是否正在执行 --- 是否有 error 信息 -- 是否成功
// self.loginBtn.rac_command =
// [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
// NSLog(@"RACCommand is %@",input);
// return [RACSignal empty];
// }];
RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
// 执行2 输入命令
NSLog(@"RACCommand createSignal %@",input);
// 登录 ---> 注册 ---- ?????
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"yy"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// 执行6
NSLog(@"销毁了---");
}];
}];
}];
// 执行信号
[command.executionSignals subscribeNext:^(id _Nullable x) {
// 执行4
NSLog(@"RACCommand executionSignals %@",x);
}];
// 最新
[[command.executionSignals switchToLatest] subscribeNext:^(id _Nullable x) {
// 执行5 [subscriber sendNext:@"yy"];
NSLog(@"RACCommand switchToLatest %@",x);
}];
// 是否正在执行 // 执行1 执行3 执行8
// addedExecutionSignalsSubject --> signal ---
// 班长 ---- 小兵 ---- 拉练习
// 排长 --- 班长
[command.executing subscribeNext:^(id _Nullable x) {
NSLog(@"RACCommand executing %@",x);
}];
// 错误
[command.errors subscribeNext:^(NSError * _Nullable x) {
NSLog(@"RACCommand errors %@",x);
}];
// 开始执行命令
[command execute:@"命令"];
}
2.RACCommand底层逻辑分析
2.1我们先看一下RACCommand
的初始化方法
2.2我们先看一下RACCommand
的initWithSignalBlock
、initWithEnabled:signalBlock
我们看到 RACCommand initWithEnabled:signalBlock
有很多属性 是用来状态 判断是否 正在来、是否在执行、是否发生错误
我们最重要的核心就是看addedExecutionSignalsSubject
,他是属于RACSubject
.RACSubject
是即可攻也可以守的。
- (instancetype)initWithSignalBlock:(RACSignal<id> * (^)(id input))signalBlock {
return [self initWithEnabled:nil signalBlock:signalBlock];
}
- (instancetype)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal<id> * (^)(id input))signalBlock {
NSCParameterAssert(signalBlock != nil);
self = [super init];
_addedExecutionSignalsSubject = [RACSubject new];
_allowsConcurrentExecutionSubject = [RACSubject new];
_signalBlock = [signalBlock copy];
_executionSignals = [[[self.addedExecutionSignalsSubject
map:^(RACSignal *signal) {
return [signal catchTo:[RACSignal empty]];
}]
deliverOn:RACScheduler.mainThreadScheduler]
setNameWithFormat:@"%@ -executionSignals", self];
// `errors` needs to be multicasted so that it picks up all
// `activeExecutionSignals` that are added.
//
// In other words, if someone subscribes to `errors` _after_ an execution
// has started, it should still receive any error from that execution.
RACMulticastConnection *errorsConnection = [[[self.addedExecutionSignalsSubject
flattenMap:^(RACSignal *signal) {
return [[signal
ignoreValues]
catch:^(NSError *error) {
return [RACSignal return:error];
}];
}]
deliverOn:RACScheduler.mainThreadScheduler]
publish];
_errors = [errorsConnection.signal setNameWithFormat:@"%@ -errors", self];
[errorsConnection connect];
RACSignal *immediateExecuting = [[[[self.addedExecutionSignalsSubject
flattenMap:^(RACSignal *signal) {
return [[[signal
catchTo:[RACSignal empty]]
then:^{
return [RACSignal return:@-1];
}]
startWith:@1];
}]
scanWithStart:@0 reduce:^(NSNumber *running, NSNumber *next) {
return @(running.integerValue + next.integerValue);
}]
map:^(NSNumber *count) {
return @(count.integerValue > 0);
}]
startWith:@NO];
_executing = [[[[[immediateExecuting
deliverOn:RACScheduler.mainThreadScheduler]
// This is useful before the first value arrives on the main thread.
startWith:@NO]
distinctUntilChanged]
replayLast]
setNameWithFormat:@"%@ -executing", self];
RACSignal *moreExecutionsAllowed = [RACSignal
if:[self.allowsConcurrentExecutionSubject startWith:@NO]
then:[RACSignal return:@YES]
else:[immediateExecuting not]];
if (enabledSignal == nil) {
enabledSignal = [RACSignal return:@YES];
} else {
enabledSignal = [enabledSignal startWith:@YES];
}
_immediateEnabled = [[[[RACSignal
combineLatest:@[ enabledSignal, moreExecutionsAllowed ]]
and]
takeUntil:self.rac_willDeallocSignal]
replayLast];
_enabled = [[[[[self.immediateEnabled
take:1]
concat:[[self.immediateEnabled skip:1] deliverOn:RACScheduler.mainThreadScheduler]]
distinctUntilChanged]
replayLast]
setNameWithFormat:@"%@ -enabled", self];
return self;
}
2.3 addedExecutionSignalsSubject
有了signal
信号 subscribeNext
订阅才有用
订阅是由addedExecutionSignalsSubject
来的 。
我们来查看addedExecutionSignalsSubject
的signal如何来的。
我们主要看execute
subscribeNext
[command.executing subscribeNext:^(id _Nullable x) {
NSLog(@"RACCommand executing %@",x);
}];
execute
打个比如:班长带兵进行排练。流程就是班长-发送指令-士兵-士兵进行排练
班长->士兵->排练
,但是班长不能自己下达这个命令,那么谁下命令给班长
.排长
.排长的作用就是相当于execute
,那么最终的班长相当于addedExecutionSignalsSubject
[command execute:@"命令"];
---
- (RACSignal *)execute:(id)input {
// `immediateEnabled` is guaranteed to send a value upon subscription, so
// -first is acceptable here.
BOOL enabled = [[self.immediateEnabled first] boolValue];
if (!enabled) {
NSError *error = [NSError errorWithDomain:RACCommandErrorDomain code:RACCommandErrorNotEnabled userInfo:@{
NSLocalizedDescriptionKey: NSLocalizedString(@"The command is disabled and cannot be executed", nil),
RACUnderlyingCommandErrorKey: self
}];
return [RACSignal error:error];
}
// 当前的block
RACSignal *signal = self.signalBlock(input);
NSCAssert(signal != nil, @"nil signal returned from signal block for value: %@", input);
// We subscribe to the signal on the main thread so that it occurs _after_
// -addActiveExecutionSignal: completes below.
//
// This means that `executing` and `enabled` will send updated values before
// the signal actually starts performing work.
// RAC关联者
// 保证信号只能执行一次
RACMulticastConnection *connection = [[signal
subscribeOn:RACScheduler.mainThreadScheduler]
multicast:[RACReplaySubject subject]];
// subscribers
// 遍历 --- subscriber --- sendNext
[self.addedExecutionSignalsSubject sendNext:connection.signal];
// 保证每个信号都能够传递
[connection connect];
return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, RACDescription(input)];
}
我们signalBlock
跟踪block回到外部 block内部可以根据input
的指令不同。操作其他事情。比如登录
、注册
RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
// 执行2 输入命令
NSLog(@"RACCommand createSignal %@",input);
// 登录 ---> 注册 ---- ?????
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"yy"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// 执行6
NSLog(@"销毁了---");
}];
}];
}];
// 执行信号
[command.executionSignals subscribeNext:^(id _Nullable x) {
// 执行4
NSLog(@"RACCommand executionSignals %@",x);
}];
我们继续往signalblock
下看
// We subscribe to the signal on the main thread so that it occurs _after_
// -addActiveExecutionSignal: completes below.
//
// This means that `executing` and `enabled` will send updated values before
// the signal actually starts performing work.
// RAC关联者
// 保证信号只能执行一次
RACMulticastConnection *connection = [[signal
subscribeOn:RACScheduler.mainThreadScheduler]
multicast:[RACReplaySubject subject]];
// subscribers
// 遍历 --- subscriber --- sendNext
[self.addedExecutionSignalsSubject sendNext:connection.signal];
// 保证每个信号都能够传递
[connection connect];