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的宏
    • 1.RAC的宏 `@weakify`拆分
  • ②、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`订阅才有用
        • subscribeNext
        • execute
        • 我们`signalBlock`跟踪block回到外部 block内部可以根据`input`的指令不同。操作其他事情。比如`登录`、`注册`
        • 我们继续往`signalblock`下看

①、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 = __weak6、#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跟116、//得出 metamacro_foreach_cxt2metamacro_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:^{// 执行6NSLog(@"销毁了---");}];}];}];// 执行信号[command.executionSignals subscribeNext:^(id  _Nullable x) {// 执行4NSLog(@"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我们先看一下RACCommandinitWithSignalBlockinitWithEnabled: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.addedExecutionSignalsSubjectmap:^(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.addedExecutionSignalsSubjectflattenMap:^(RACSignal *signal) {return [[signalignoreValues]catch:^(NSError *error) {return [RACSignal return:error];}];}]deliverOn:RACScheduler.mainThreadScheduler]publish];_errors = [errorsConnection.signal setNameWithFormat:@"%@ -errors", self];[errorsConnection connect];RACSignal *immediateExecuting = [[[[self.addedExecutionSignalsSubjectflattenMap:^(RACSignal *signal) {return [[[signalcatchTo:[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 = [[[[[immediateExecutingdeliverOn:RACScheduler.mainThreadScheduler]// This is useful before the first value arrives on the main thread.startWith:@NO]distinctUntilChanged]replayLast]setNameWithFormat:@"%@ -executing", self];RACSignal *moreExecutionsAllowed = [RACSignalif:[self.allowsConcurrentExecutionSubject startWith:@NO]then:[RACSignal return:@YES]else:[immediateExecuting not]];if (enabledSignal == nil) {enabledSignal = [RACSignal return:@YES];} else {enabledSignal = [enabledSignal startWith:@YES];}_immediateEnabled = [[[[RACSignalcombineLatest:@[ enabledSignal, moreExecutionsAllowed ]]and]takeUntil:self.rac_willDeallocSignal]replayLast];_enabled = [[[[[self.immediateEnabledtake: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];}// 当前的blockRACSignal *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 = [[signalsubscribeOn: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:^{// 执行6NSLog(@"销毁了---");}];}];}];// 执行信号[command.executionSignals subscribeNext:^(id  _Nullable x) {// 执行4NSLog(@"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 = [[signalsubscribeOn:RACScheduler.mainThreadScheduler]multicast:[RACReplaySubject subject]];// subscribers// 遍历 --- subscriber --- sendNext[self.addedExecutionSignalsSubject sendNext:connection.signal];// 保证每个信号都能够传递[connection connect];

③、iOS-RAC-底层分析-RAC的宏-RACCommand相关推荐

  1. ①、iOS-RAC的开发用法-底层分析以及总结

    iOS RAC系列 ①.iOS-RAC的开发用法-底层分析以及总结 ②.iOS-RAC-核心类分析-RACPassthroughSubscriber订阅者-RACScheduler调度者-RACDis ...

  2. RAC(ReactiveCocoa)之 RAC宏定义

    在编程领域里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式.解释器在遇到宏时会自动进行这一模式替换.绝大多数情况下,"宏"这个词的使用暗示着将 ...

  3. 深入iOS系统底层之静态库介绍

    少长咸集,群贤毕至.--<王羲之・兰亭集序> 目标文件 目标文件结构 程序员编写的是源代码,而计算机运行的则是CPU能识别的机器指令,因此必须要有一系列工具或程序来将源代码转化为机器指令, ...

  4. android 4.4 电池电量管理底层分析(C\C++层)

    参考文献:http://blog.csdn.net/wlwl0071986/article/details/38778897 简介: Linux电池驱动用于和PMIC交互.负责监听电池产生的相关事件, ...

  5. iOS crash 问题分析汇总

    在这里插入图片描述 iOS crash 问题分析 iOS crash 常用分析工具 IOS 崩溃日志 iOS crash 原因分析 1.调用悬浮指针 2.数组越界访问 3.调用了未实现的方法 4.调用 ...

  6. oracle rac应急_oracle rac 多数据库

    Oracle系列:Oracle RAC集群体系结构 一. Oracle集群体系结构 Oracle RAC,全称是Oracle Real Application Cluster,即真正的应用集群,是or ...

  7. 深入iOS系统底层之CPU寄存器介绍

    一弹指六十刹那,一刹那九百生灭. --<仁王经> 组件 计算机是一种数据处理设备,它由CPU和内存以及外部设备组成.CPU负责数据处理,内存负责存储,外部设备负责数据的输入和输出,它们之间 ...

  8. Android底层隐私数据,Android Intent传递数据底层分析详细介绍_Android_脚本之家

    Android  Intent传递数据底层分析详细介绍 我们知道在Activity切换时,如果需要向下一个ActivityB传递数据,可以借助Intent对象的putExtra方法. 但是不知各位有没 ...

  9. 【Python基础避坑】函数内存底层分析,全局变量/局部变量,参数传递,浅拷贝/深拷贝

    老高说,基本功不扎实会在工作中遇到很多的坑,非常同意- 函数定义示例 1.含有返回值 # -*-coding:utf-8-*- def add(a, b):'''两数相加'''sum = a + br ...

最新文章

  1. 2021-2027年中国视频监控设备行业市场需求预测与投资战略规划分析报告
  2. 水泵怎么做_不是说鱼缸里放置三合一水泵都会起到反作用,也得看什么缸什么鱼...
  3. js 改变change方法_Linux 中改变主机名的 4 种方法 | Linux 中国
  4. poj 2985(并查集+线段树求K大数)
  5. 经典的 Fork 炸弹解析
  6. 程序员吐槽_阿里程序员回老家被哥们吐槽,破IT就破IT,还阿里巴巴
  7. Activiti6.0教程 Eclipse安装Activiti Diagram插件(一)
  8. [HAOI2008]玩具取名
  9. ***站长自述挂马经历 提醒挂马者回头是岸
  10. 算法工程师的冰与火之歌
  11. Unity 移动端的复制这么写
  12. AtCoder Beginner Contest 223
  13. OpenCV中寻找轮廓函数cvFindContours的使用说明以及序列cvSeq的用法说明
  14. 软件开发工作的绩效评估
  15. 18款口碑爆棚手机浏览器,被一网打尽了
  16. 2022最新WiFi大师小程序V3.0.9独立版源码
  17. 基于Domoticz智能家居系统(十三)Domoticz-3.8153在Tiny6410开发板上的移植
  18. C++泰勒公式实现反余弦函数
  19. 导盲机器人 英语作文_雷军这回OK了!小米或将推出会说英文的 AI 自平衡车
  20. excel两列乱序姓名如何一一对应 excel 两列数据自动配对

热门文章

  1. (可远程)ESP8266读DHT11温湿度,APP inventor制作app实时显示
  2. 计算机系统报名可以win10吗,怎么看自己的电脑适不适合装win10_如何检测电脑是否可以升级安装win10系统...
  3. binwalk 的安装和使用
  4. html页面遍历map,map遍历的几种方式是什么?
  5. 关于0x0d与0x0a的ASCII。
  6. 微信小程序uni-app前端应用框架和HBuilderX工具使用及Git管理项目
  7. springboot 返回json串含有斜杠
  8. gitlab 删除远程分支
  9. 对removeAttr()和splice()的使用。
  10. java实现王者荣耀匹配规则,王者荣耀匹配机制故意安排队友,看看队友构成就知道了...