text: OCMethodTrace - Trace Any Objective-C Method Calls
  ===========================
  跟踪打印Objective-C任何实例(类)方法
  
  ## 功能：
  1. 支持任意OC实例(类)方法的跟踪打印
  2. 支持多架构(arm32，arm64，i386，x86_64)
  3. 支持跟踪父类和子类相同的方法
  4. 支持各种灵活配置，包括方法黑白名单等
  
  ## 配置说明：
  ### 全局配置：
  #### LogLevel：Trace日志级别，对应MDTraceLogLevel，必须定义，默认值：0
      0：MDTraceLogLeveError，错误级别
      1：MDTraceLogLeveDebug，调试级别
  
  #### LogWhen：Trace日志输出时机，对应MDTraceLogWhen，必须定义，默认值：0
      0：MDTraceLogWhenStartup ，启动即输出日志
      1：MDTraceLogWhenVolume ，根据音量键控制输出日志(增加音量:输出日志;降低音量:关闭日志;默认时关闭日志)
      2：MDTraceLogWhenRegexString ，输出日志包含匹配字符串才输出日志
      
      LogRegexString：日志正则匹配字符串，仅当logWhen=MDTraceLogWhenRegexString有效。日志包含指定正则字符串才输出日志
  
  #### TraceFlag：Trace控制位(尽量在该处扩展)，对应MDTraceFlag，全局必须定义，默认值：0x02，指定类可选定义，默认值：0x00
      0x01：MDTraceFlagDoesNotUseDescription，跳过调用对象description方法，避免不正规的description实现导致递归
      0x02：MDTraceFlagDumpClassListInfo，打印类列表信息，便于调试
      0x04：MDTraceFlagDumpClassMethod，打印某个类的方法(不包括父类方法)，便于调试
      0x08：MDTraceFlagDumpSuperClassMethod，打印某个类的父类方法(包括递归父类的方法)，便于调试
  
  #### TraceObject：Trace对象，对应TraceObject，必须定义，默认值：1
      0：MDTraceObjectNone，屏蔽trace所有类
      1：MDTraceObjectCoreClass，trace引擎指定类的方法(仅测试验证使用)，仅需要考虑CORE_CLASS_LIST
      2：MDTraceObjectUserClass，trace用户指定类的方法，需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集"
      3：MDTraceObjectRegexClass，trace用户指定类 + 正则匹配类的方法，需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集" + "匹配ClassRegexString的CLASS_LIST和CORE_CLASS_LIST交集"
      
      MDTraceObjectUserClass和MDTraceObjectRegexClass的区别：
      * MDTraceObjectUserClass：在考虑USER_CLASS_LIST指定的类的时候，如果USER_CLASS_LIST和CORE_CLASS_LIST存在部分交集，交集对应的类需要合并，合并算法详见：+[MDTraceClassInfo mergeInfoWithCoreInfo:userInfo:userInfo:]
      * MDTraceObjectRegexClass：在考虑MDTraceObjectUserClass的基础上，再考虑ClassRegexString正则匹配的类。
  
      处理TraceObject的详细算法见：-[ MDMethodTrace parseClassListInfo]，算法内部注意优先级顺序：core > user > regex
      
  ### 指定类配置：
  #### USER_CLASS_LIST：用户指定类列表，必须定义
      TraceMode： Trace模式，对应MDTraceMode，可选定义，默认值：1
          0：MDTraceModeOff，屏蔽trace方法
          1：MDTraceModeAll，trace所有方法
          2：MDTraceModeIncludeWhiteList，trace包含"白名单方法列表"的方法
          3：MDTraceModeExcludeBlackList，trace排除"黑名单方法列表"的方法
      TraceFlag：定义同全局配置，但是粒度更小，属于某个类范围内，可选定义，默认值：0x00
      MethodWhiteList：白名单方法列表，可选定义，但MDTraceModeIncludeWhiteList时必须定义
      MethodBlackList：黑名单方法列表，可选定义，但MDTraceModeExcludeBlackList时必须定义
  
  #### CORE_CLASS_LIST：引擎指定类列表，必须定义
      TraceMode：定义同USER_CLASS_LIST的TraceMode，但是仅支持MDTraceModeOff和MDTraceModeExcludeBlackList
      TraceFlag：定义同全局配置，但是粒度更小，属于某个类范围内，可选定义，默认值：0x00
      MethodBlackList：黑名单方法列表，可选定义，但MDTraceModeExcludeBlackList时必须定义
  
  #### ClassRegexString：类正则匹配字符串，仅TraceObject=MDTraceObjectRegexClass有效
      每个匹配的类使用默认类配置(可以理解成一个默认的User类)。使用场景：在不确定trace哪些类的情况下，批量trace一些有规律命名方式的类，匹配字符串如：“Notification|^CM|(F|f)igCaptureSource”
  
  
  #### USER_CLASS_LIST和CORE_CLASS_LIST的关系：
      * CORE_CLASS_LIST：存在的意义在于，OCMethodTrace框架(引擎)内部也需要调用一些OC类方法，为了保证整个框架可以跑起来，避免trace到框架内部使用到的类导致的打印递归循环，所以，需排除这些指定类的全部方法或者部分方法。
      * USER_CLASS_LIST：用户自己指定的类，可以任意发挥。但是如果CORE_CLASS_LIST有相同的类，会优先CORE_CLASS_LIST中的配置。合并算法详见"+[MDTraceClassInfo mergeInfoWithCoreInfo:userInfo:userInfo:]"
  
  ## 技术要点：
  ### 支持跟踪父类和子类相同的方法  
      SatanWoo提出了一个方法(见感谢2)，使用“runtime的消息转发机制+跳板原理(桥)”实现，流程：
      每个方法置换到不同的IMP桥上 -> 从桥上反推出当前的调用关系（class和selector）-> 构造一个中间态新名字 -> forwardingTargetForSelector(self, 中间态新名字) 。
      但是SatanWoo的demo(见感谢3)有两个比较大的缺陷：
      * 仅支持arm64平台，不支持多架构；
      * 仅支持实例方法，不支持类方法。
      为此我做了一些改进，如下：
      * 支持多架构：参考objc4(见感谢4)的objc-block-trampolines.m，编写了一个通用的跳板实现，其中通过汇编支持多架构。
      * 支持类方法：NSObject (OCMethodTrace)需hook类方法"+[NSObject forwardingTargetForSelector:]"
  ### Trace输出无限循环递归的特殊处理
      递归调用都发生在"-[OCMethodTrace omt_forwardInvocation:]"函数内部，有两个地方：
      * 对象调用自身的description导致的无限递归：为了打印对象的描述，需要调用对象的description方法，而该方法内部很可能会调用对象的其它内部方法，继而递归又调用"-[OCMethodTrace omt_forwardInvocation:]"，于是无限循环。当前解决的方法是：在"-[OCMethodTrace omt_forwardInvocation:]"开始处通过遍历函数堆栈链查找"OMTBlockRunBeforeSelector"，"OMTBlockRunAfterSelector"和"OMTDescriptionWithTargetSelector"这几个方法，可以知道是否存在递归，发现递归就不要再调用runBefore和runAfter回调即可。缺点：遍历函数堆栈链的方法实在不优雅，而且性能也受影响，需要优化！
      * OCMethodTrace框架使用到的基础类导致的无限递归：比如"-[OCMethodTrace omt_forwardInvocation:]"函数范围内用到一些类：如NSDate，NSString或者runBefore或runAfter回调用到的方法等，一旦他们也被trace，也会导致循环递归。解决的思路是：把这些类放在黑名单里，不再trace。当然还有降低循环递归的方式是，内部实现尽量使用C或者C++实现。
  
  ## TODO：
  1. 通过遍历堆栈链，判断是否存在循环递归调用的算法性能太差，需优化。
  2. 开启全局dump类方法(MDTraceFlagDumpClassMethod)容易导致异常，不建议开启。
  
  ## 感谢：
  1. https://github.com/qhd/ANYMethodLog
  2. https://satanwoo.github.io/2017/09/24/mainthreadchecker1
  3. https://github.com/SatanWoo/MainThreadChecker.git
  4. https://opensource.apple.com/tarballs/objc4/objc4-723.tar.gz
  
  欢迎提Issues和Pull requests，如有问题，可以联系 Michael Chen (omxcodec@gmail.com)
  