iOS 开发:Method Swizzling
iOS 开发之Method Swizzling
前言
如果你还不知道什么是Method Swizzling,你可以看看NSHipster 的文章 ,我简单介绍一下,method swizzling 可以看成劫持了一个方法。
我们可以看看NSHipster 的文章中有以下代码:
- (void)xxx_viewWillAppear:(BOOL)animated {[self xxx_viewWillAppear:animated];NSLog(@"viewWillAppear: %@", self);
}
是不是觉得递归无限循环,事实上并不会,你可以这么理解,一个具体的SEL是个名字,一个具体的IMP是个函数指针,在类里面它们是靠一个表建立联系。
假设(纯属虚构) UIViewController 的 @selector(viewWillAppear:) 对应的内部实现为以下
void _UIKIT_Internal_UIViewController_viewWillAppear(id vc, SEL selector, BOOL animated) {...// ^_^苹果私有代码
}
假设UIViewController 的 @selector(xxx_viewWillAppear:) 的实现为以下
void my_xxx_viewWillAppear(id vc, SEL selector, BOOL animated) {[vc performSelector:@selector(xxx_viewWillAppear) withObject:@(animated)]; NSLog(@"viewWillAppear: %@", vc);
}
那么未替换方法前@selector(viewWillAppear:)对应的指针就是&_UIKIT_Internal_UIViewController_viewWillAppear
那么未替换方法前@selector(xxx_viewWillAppear:)对应的指针就是&my_xxx_viewWillAppear
一旦替换方法后,@selector(viewWillAppear:)对应的指针就是&my_xxx_viewWillAppear,
@selector(xxx_viewWillAppear:)对应的指针就是&_UIKIT_Internal_UIViewController_viewWillAppear
my_xxx_viewWillAppear 中的 [vc performSelector:@selector(xxx_viewWillAppear) withObject:@(animated)];
相当于什么,相当于 调用@selector(xxx_viewWillAppear:)所指的函数&_UIKIT_Internal_UIViewController_viewWillAppear, 也就是相当于调用原来的函数,所以这并不是递归。
存在的危险
- 有些NSObject类是类簇,替换方法要找到真正的类,如NSArray替换方法,通常用'_NSArrayM'或'_NSArrayI'
- 执行顺序问题,ViewController是自己写的类,ViewController的load方法和UIViewController的category里的load方法哪个先执行,如果是ViewController的先执行,那么UIViewController的swizzling就对ViewController无效,如果ViewController的后执行就一切正常,代码如下
@implementation UIViewController (Tracking)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{[self replaceOriginalSelector:@selector(viewWillAppear:) withNewSelector:@selector(xxx_viewWillAppear:)];});
}- (void)xxx_viewWillAppear:(BOOL)animated {[self xxx_viewWillAppear:animated];NSLog(@"x_viewWillAppear: %@", self);
}
@end@interface ViewController ()@end@implementation ViewController+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{[self replaceOriginalSelector:@selector(viewWillAppear:) withNewSelector:@selector(yyy_viewWillAppear:)];});
}- (void)yyy_viewWillAppear:(BOOL)animated {[self yyy_viewWillAppear:animated];NSLog(@"y_viewWillAppear: %@", self);
}@end
3.也是顺序问题
以下,来自另一篇文章defagos.github.io
它是这么说的,NSObject 实现了 -awakeFromNib,但是它的子类UIView,孙类UILabel都没有在本类实现- awakeFromNib,那么替换时如果不写在category +(void) load方法里,那么顺序也是个问题
假设我们先替换了UILabel的- awakeFromNib方法,然后再替换了UIView的- awakeFromNib,那么UILabel的- awakeFromNib方法就不会执行UIView的- awakeFromNib方法,因为它们都是独立替换的是NSObject方法,这篇文章defagos.github.io 提供了一个解决方案,当本类没有实现方法(如 UILabel -awakeFromNib)时,首先先添加一个block方法 调用[super awakeFromNib];,我初次看到也是觉得这个方式很好,但是我发现两点不足,
在构建objc_super时,如果父类本身没有实现方法,.super_class = class_getSuperclass(clazz),这么写好像是没有用的,似乎super_class要填真正实现方法的祖先类,而不能一概的写class_getSuperclass
struct objc_super super = {.receiver = self,.super_class = class_getSuperclass(clazz)};
- va_list的使用
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
由于 va_list 变量最后是靠宏 va_arg(ap, type)
来获取的,type又是未知的,这个函数指针的强制转换转换可能会出现问题
结语
可见,Swizzling正确的顺序是十分重要的,(共同点:类本身没有真正实现方法)
- 如果你的Swizzling是静态的,那么就保证父类的Swizzling发生在子类的Swizzling前
- 如果你的Swizzling是动态的或者你管不好他们先后顺序,那么就要用defagos的方法动态的call objc_msgSendSuper,
- 或许你勤快一点还可以直接在category里面重写,
- (void)awakeFromNib { [super awakeFromNib]; }
转载于:https://blog.51cto.com/14033137/2309805
iOS 开发:Method Swizzling相关推荐
- iOS黑魔法--Method Swizzling
参考链接: iOS黑魔法-Method Swizzling iOS 黑魔法 - 专题 - 简书 Method Swizzle黑魔法,修改 ios 系统类库方法
- iOS 开发:『Runtime』详解(二)Method Swizzling
本文用来介绍 iOS 开发中『Runtime』中的黑魔法Method Swizzling. 通过本文,您将了解到: Method Swizzling(动态方法交换)简介 Method Swizzlin ...
- 【原】iOS动态性(三) Method Swizzling以及AOP编程:在运行时进行代码注入
概述 今天我们主要讨论iOS runtime中的一种黑色技术,称为Method Swizzling.字面上理解Method Swizzling可能比较晦涩难懂,毕竟不是中文,不过你可以理解为" ...
- iOS总结-Runtime篇之黑魔法Method Swizzling的滥用会有危险吗
参考https://www.jianshu.com/p/19c5736c5d9a, http://blog.sina.com.cn/s/blog_a343f32b0101en4o.html runti ...
- 关于Swift4.0 Method Swizzling(iOS的hook机制)使用
2019独角兽企业重金招聘Python工程师标准>>> 关于Method Swizzling 原理什么的有很多帖子讲述的已经很清楚这里不再赘述, 这里仅仅处理Method Swizz ...
- iOS总结-Runtime篇之用途及面试题的总结一黑魔法Method Swizzling
runtime的用途基本分下面几类: 实现多继承Multiple Inheritance 上一篇里面的最后利用methodSignatureForSelector来进行一次转发,在forwardInv ...
- 【转】几点 iOS 开发技巧
[译] 几点 iOS 开发技巧 原文:iOS Programming Architecture and Design Guidelines 原文来自破船的分享 原文作者是开发界中知晓度相当高的 Mug ...
- iOS 开发面试通关指南:67 个必知问题!
作者 | Artur Rymarz 译者 | 香槟超新星,责编 | 郭芮 出品 | CSDN(ID:CSDNnews) 以下为译文: 我们都知道,面试可能会让人感到压力山大--不管你是第一次参加面试的 ...
- 唐巧的《iOS开发进阶》 - 读后感
2019独角兽企业重金招聘Python工程师标准>>> 唐巧的<iOS开发进阶> - 读后感 为什么要看书 为什么要多看书呢? 在技术类书籍上,看书的目的,不是为了记住所 ...
- 【原】iOS开发进阶(唐巧)读书笔记(二)
第三部分:iOS开发底层原理 1.Objective-C对象模型 1.1 isa指针 NSObject.h部分代码: NS_ROOT_CLASS @interface NSObject <NSO ...
最新文章
- 个人开发者即时到账收款方案 BufPay.com
- 三维点云分割综述(中)
- 巧用Ajax的beforeSend 提高用户体验--防止重复数据
- 数据库路由中间件MyCat - 使用篇(2)
- 无重复字符的最长子串—leetcode3
- 有限元python编程流行吗_Python进行有限元分析
- Cow Contest(POJ-3660 )
- Python中__init__和__del__方法介绍
- 下行物理信道rs_LTE下行物理信道与物理信号
- Angular导入导出Excel控件简介
- 无线网络密码破解方法
- 传奇服务器文件组成,【教程】传奇服务端(版本)的结构以及重要文件功能的概述-A02...
- Dreamweaver CS6 行为概述
- chromium 下载地址
- 最新北京人才公寓申请流程,技术员的福利~
- 百度没有文化(转载)
- Ubuntu+Sendmail+Dovecot+Openwebmail 邮件服务器搭建完全解决方案
- 如何在线赚钱:28 种真正的在线赚钱方式
- Linux搭建邮箱服务器
- butter滤波器是iir吗_MATLAB IIR滤波器设计函数buttord与butter
热门文章
- Java Web开发实战(二)—Tomcat安装及环境变量配置
- npm:no such file /usr/local/lib/node_modules/vue-cli/node_modules/get-stream
- php从入门到精通分享,PHP从入门到精通学习路线图分享
- Go github.com/e421083458/golang_common/lib
- $.each 中return问题
- 用PHP写Yaf:Yaf_Registry类
- plesk 打不开php,如何在 Plesk 中管理 PHP
- java1.8移除apt,java 1.8上的maven-enunciate-plugin现在从最新的JDK中删除了(即java注释处理工具)...
- OFFICE技术讲座:关于坐标、位置的术语说明
- 做出产品不难,做好产品必须高手