当前位置: 代码迷 >> 综合 >> UIViewController-Swizzled【iOS源码阅读】
  详细解决方案

UIViewController-Swizzled【iOS源码阅读】

热度:32   发布时间:2023-12-15 01:39:16.0

转自:http://blog.csdn.net/liaohongwei/article/details/52625595

实现的功能

    可用于跟踪复杂程序的一个非常简单的类库源码,查看每个viewController的层级嵌套顺序


     显示一个UIViewController的时候日志记录一下

原理

     hook UIViewController 的 viewDidAppear: 方法

     Objecitve-C的重要特性是Runtime(运行时),在Interacting with the Runtime(交互运行)中,运行时函数部分,苹果给出了/usr/lib/libobjc.A.dylib库,这个共享库提供支持动态属性的objective - c语言,通过其接口,可以用于开发将其他语言运行于Objective-C上的中间层(桥接层),库里的函数定义为纯C语言。

     其中#import <objc/runtime.h>运行时确认函数用于动态调用, 代码中:
   
    
  1. +(void)load
  2. {
  3.     isSwizzed = NO;
  4. }

     一般情况下,类别里的方法会重写掉主类里相同命名的方法。如果有两个类别实现了相同命名的方法,只有一个方法会被调用。但 +load: 是个特例,当一个类被读到内存的时候, runtime 会给这个类及它的每一个类别都发送一个 +load: 消息。

     用于记录每个只会flag一次

   
    
  1. -(void)swizzviewDidAppear:(BOOL)animated
  2. {
  3.     [self printPath];
  4.     // Call the original method (viewWillAppear)
  5.     [self swizzviewDidAppear:animated];
  6. }
     代码看起来可能有点奇怪,像递归不是么。当然不会是递归,因为在 runtime 的时候,函数实现已经被交换了。调用 viewDidAppear: 会调用你实现的 swizzled_viewDidAppear:,而在 swizzled_viewDidAppear: 里调用 swizzled_viewDidAppear: 实际上调用的是原来的 viewDidAppear: 

    所以效果就是viewDidAppear的调用会先执行swizzviewDidAppear,再执行swizzviewDidAppear里的swizzviewDidAppear(也就是原来viewDidAppear里实现的代码)


函数替换

  • class_getInstanceMethod
  • class_addMethod
  • class_replaceMethod

源码地址

  • https://github.com/RuiAAPeres/UIViewController-Swizzled

黑魔法

     Objective-C 的运行时中最具争议的黑魔法:method swizzling: http://nshipster.cn/method-swizzling/