ObjC Runtime 黑魔法 — Method Swizzling

适用情境

项目中大量控制器需要在载入时进行日志统计或进行类似的处理。如果直接往所有控制器中进行代码编写,会产生大量的重复的代码,降低了代码后期的可读性,不利于维护。由于所有部分的逻辑代码相同,针对这种情况,以切面编程(AOP)思想为导向,利用 Method Swizzling 能极大降低这种(日志统计)非主要逻辑代码与控制器的耦合度。

AOP概念详解(摘自百度百科)

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

通过Demo来学习(MethodSwizzling_Demo)

1. 创建一个空工程,再为工程中的 ViewController类创建一个分类(Logging)。

2. 在ViewController 中重载 viewDidAppear: 方法。

- (void)viewDidAppear:(BOOL)animated {
    
    [super viewDidAppear:animated];
}

3. 如果每当该控制器被用户选中后,我们都想在控制台通过输出消息观测到,那么应该向 viewDidAppear: 中添加

NSlog(@"%@", NSStringFromClass([self class]));

以输出设备当前显示的视图所属的控制器。

4. 如果现在需要进行步骤3修改的控制器数量庞大,显然,我们需要另想办法。

5. 在 UIViewController+Logging.m 中导入头文件 objc/runtime.h ,现在我们就要利用 Method Swizzling 来处理这个问题。

6. 在分类的实现文件中添加方法

- (void)swizzled_viewDidAppear:(BOOL)animated {
    
    [self swizzled_viewDidAppear:animated];
    NSLog(@"%@", NSStringFromClass([self class]));
}

该方法把我们需要添加到所有控制器的逻辑代码集结到了一处。

7. 在分类中继续实现以下方法

void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
   /* 判断 class 中是否存在以 originalSelector 为方法名的 方法。
    * 若没有,则添加 以 originalSelector 为方法名,
    * 以 swizzledMethod 为实现的方法!
    * 若有,则不添加。
    */
    /* 不直接进行 method_exchangeImplementations 替换的原因: 如果这个类没有实现 originalSelector,但是其父     * 类实现了, 那么 class_getInstanceMethod 会返回父类的方法。这样,method_exchangeImplementations 替换      * 的是父类的那个方法
     */
    BOOL didAddMethod = class_addMethod( class, originalSelector, 
    method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSelector, method_getImplementatino(originalMethod), method_g    etTypeEncoding(originalMethod));
    } 
    else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

8. 为了使用分类中我们写好的 swizzled_viewDidAppear: 来替换控制器中的 viewDidAppear: 方法。使用一个比较特殊的方法 +(void)load 。

一般情况下,类别里的方法会重写掉主类里相同命名的方法。如果有两个类别实现了相同命名的方法,只有一个方法会被调用。

但 +load: 是个特例,当一个类被读到内存的时候, runtime 会给这个类及它的每一个分类都发送一个 +load: 消息。

9. 在分类实现中加入

+ (void)load {
    
    swizzleMethod([self class], @selector(viewDidAppear:), @selector(swizzled_viewDidAppear:));
}

swizzleMethod 对方法名为 viewDidAppear: 和 方法名为 swizzled_viewDidAppear: 两个方法的实现部分进行互换。

注意: @selector(viewDidAppear:)中的 viewDidAppear: 方法是 UIViewController 类中的,不是其子类 ViewController 中的。

10. 调用过程见下图

时间: 2024-10-02 04:49:46

ObjC Runtime 黑魔法 — Method Swizzling的相关文章

iOS runtime探究(四): 从runtiem开始实践Category添加属性与黑魔法method swizzling

你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639335 本文主要讲解runtime相关知识,从原理到实践,由于包含内容过多分为以下五篇文章详细讲解,可自行选择需要了解的方向: 从runtime开始: 理解面向对象的类到面向过程的结构体 从runtime开始: 深入理解OC消息转发机制 从runtime开始: 理解OC的属性property 从runtime开始: 实践Category添加属

iOS黑魔法-Method Swizzling

公司年底要在新年前发一个版本,最近一直很忙,好久没有更新博客了.正好现在新版本开发的差不多了,抽空总结一下.由于最近开发新版本,就避免不了在开发和调试过程中引起崩溃,以及诱发一些之前的bug导致的崩溃.而且项目比较大也很不好排查,正好想起之前研究过的Method Swizzling,考虑是否能用这个苹果的“黑魔法”解决问题,当然用好这个黑魔法并不局限于解决这些问题...... 需求 就拿我们公司项目来说吧,我们公司是做导航的,而且项目规模比较大,各个控制器功能都已经实现.突然有一天老大过来,说我

Objective-C Runtime Method Swizzling 实践

直接上代码 1  交换实例方法: + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //交换的是实例方法 Class class = [self class]; SEL originalSelector = @selector(originMethod);//originMethod 已经存在的方法 SEL swizzleSelector = @selector(swizzleMethod)

iOS开发之 Method Swizzling 深入浅出

<p align="center"><img src ="https://raw.githubusercontent.com/DotzuX/Notes/master/logo.jpeg"/></p> iOS开发之 Method Swizzling 深入浅出 只要善用Google,网上有很多关于Method Swizzling的Demo,在这里我就不打算贴代码了,主要介绍下概念,原理,注意事项等等. 开发需求 如果产品经理突然说:&

iOS 使用Method Swizzling隐藏Status Bar

在iOS 6中,隐藏Status Bar非常的简单. // iOS 6及以前,隐藏状态栏 [[UIApplication sharedApplication] setStatusBarHidden:YES]; 来到了iOS 7的年代以后,需要在UIViewController中指定: #ifdef __IPHONE_7_0 - (BOOL)prefersStatusBarHidden { return YES; } #endif 并通过下列代码刷新状态栏: if ([viewController

Method Swizzling 和 AOP 实践(转)

上一篇介绍了 Objective-C Messaging.利用 Objective-C 的 Runtime 特性,我们可以给语言做扩展,帮助解决项目开发中的一些设计和技术问题.这一篇,我们来探索一些利用 Objective-C Runtime 的黑色技巧.这些技巧中最具争议的或许就是 Method Swizzling . 介绍一个技巧,最好的方式就是提出具体的需求,然后用它跟其他的解决方法做比较. 所以,先来看看我们的需求:对 App 的用户行为进行追踪和分析.简单说,就是当用户看到某个 Vie

Objective-C Runtime 运行时之四:Method Swizzling

理解Method Swizzling是学习runtime机制的一个很好的机会.在此不多做整理,仅翻译由Mattt Thompson发表于nshipster的Method Swizzling一文. Method Swizzling是改变一个selector的实际实现的技术.通过这一技术,我们可以在运行时通过修改类的分发表中selector对应的函数,来修改方法的实现. 例如,我们想跟踪在程序中每一个view controller展示给用户的次数:当然,我们可以在每个view controller的

runtime 第四部分method swizzling

接上一篇 http://www.cnblogs.com/ddavidXu/p/5924597.html 转载来源http://www.jianshu.com/p/6b905584f536 http://southpeak.github.io/2014/10/30/objective-c-runtime-2/ runtime的黑魔法,就是可以实现交换两个方法的实现,这就意味着我们可以修改系统的方法实现. 栗子:当UIViewController及其子类的对象调用viewWillAppear时,都会

Objective-C Runtime 运行时之四:Method Swizzling(转载)

理解Method Swizzling是学习runtime机制的一个很好的机会.在此不多做整理,仅翻译由Mattt Thompson发表于nshipster的Method Swizzling一文. Method Swizzling是改变一个selector的实际实现的技术.通过这一技术,我们可以在运行时通过修改类的分发表中selector对应的函数,来修改方法的实现. 例如,我们想跟踪在程序中每一个view controller展示给用户的次数:当然,我们可以在每个view controller的