isa swizzling 不求甚解

Tags
iOS
Draft
Date
May 19, 2021
重新认识 Method Swizzling
之前写了method swizzling的重新认识,这篇isa swizzling就只能是不求甚解了。
 
A pointer to the class definition of which this object is an instance.
实例对象的isa,是一个指向该对象的类的指针。
isa swizzling,表示修改一个对象的isa,指向另一个类的指针。
以下方法效果类似
  1. object_setClass
  1. self->isa = g_zombieClass;
  1. memcpy(obj, &g_zombieClass, sizeof(void*));
 
下面我们来看看有哪些地方用到了这个技术。

KVO

最典型的例子当属官方的KVO
Automatic key-value observing is implemented using a technique called isa-swizzling.

Zombie Objects

notion image
Xcode调试内存问题的Zombie Objects技术,通过保存释放对象的内存地址,使得更容易检测内存错误(EXC_BAD_ACCESS)。
我们也可以自己实现。
或者参考网易杭州前端技术部的对于线上环境的野指针Crash防护
iOS APP运行时Crash自动修复系统
大白( Baymax ),迪士尼动画《超能陆战队》中的健康机器人,是一个体型胖胖的充气机器人,因呆萌的外表和善良的本质获得大家的喜爱,被称为"萌神"。 Baymax 项目是为了减少开发人员在开发中一些不规范的代码编写造成的内存泄露,界面卡顿,耗电等问题而来的一个监控系统。 现在Baymax迎来了它新的功能:APP运行时Crash自动防护功能,为app的流程顺利运行保驾护航! 下面将详细介绍一下 APP运行时Crash自动修复系统 开发的目的,设计的原理以及使用的方法。 是否存在这样的夜晚,当刚刚躺下准备美美的睡一觉的时候, 突然来一记夺命电话Call,一接起来发现是你老板!!!"小王啊,刚刚上线的X.X.X版本出问题了啊,怎么样操作会crash啊,导致新功能都无法使用了,快定位一下是什么原因,抓紧hotpatch修复一下啊!"。心里一万头草泥马呼啸而过,瞬间已经满头大汗的你却还要故作镇静地回答:"嗯,老板我马上去看看,一定努力解决问题!" 急忙打开电脑的你,知道今夜注定无眠了。 是否又存在这样的情形,你老板把大家都聚起来开了一个年初KPI目标制定会议,说到:"作为一个资深的技术团队,app性能是我们技术团队首抓的目标,其中很最要的一项就是app的崩溃率,去年我们app统计出来的崩溃率是千分之五,而我们的竞争对手的崩溃率只有万分之五,相差了10倍!今年我们要赶超他们,最起码也要和他们持平。" 你甚是赞同,但是你心里却又有点怀疑,对方的开发资源是我们的好几倍而且个个都是资深老司机,我们团队里却大多都是应届生小鲜肉,这KPI能完成么? 如果你遇到过以上的情况并且对此深表头痛的话,那么 大白健康系统--APP运行时Crash自动修复系统 将会是你的不二选择! APP运行时Crash自动修复+捕获系统 的设计初衷,就是为了降低app的crash率。利用Objective-C语言的动态特性,采用 AOP(Aspect Oriented Programming) 面向切面编程的设计思想,做到无痕植入。能够 自动在app运行时实时捕获导致app崩溃的破环因子,然后通过特定的技术手段去化解这些破坏因子,使app免于崩溃,照样可以继续正常运行,为app的持续运转保驾护航 。 APP运行时Crash自动修复系统 的主要功能,可以用一句话来简单的概括: 对业务代码的零侵入性地将原本会导致app崩溃的crash抓取住,消灭掉,保证app继续正常地运行,再将crash的具体信息提取出来,实时返回给用户 。 通过下面的一个小例子就可以很直观的体现出来系统的作用: 调用以下的一段代码 //test code UIButton * testObj = [[UIButton alloc] init]; [testObj performSelector:@selector(someMethod:)]; 结果肯定会导致app的崩溃,因为testObj是一个UIButton对象,而UIButton并没有实现 someMethod: 这个方法,所以向testObj发送someMethod:这个方法的时候,将会导致该方法无法在相关的方法列表里找到,最终导致app的crash。 可见对应的crash的信息(crash类型,原因,调用栈信息)均可以完整的打印在XCode的Console中。 说明我们的大白系统已经捕捉到了这个crash,将该crash消灭掉并且吐出来该crash的完整信息。 当然目前系统的功能并没有强大到可以把所有的crash都处理掉,不过一些常见的高频次发生的crash,系统均会针对他们一一处理。目前可以处理掉的crash类型具体有以下几种: unrecognized selector crash KVO crash NSNotification crash NSTimer crash Container crash(数组越界,插nil等) NSString crash (字符串操作的crash) Bad Access crash (野指针) UI not on Main Thread Crash (非主线程刷UI(机制待改善)) 对于每种类型的crash,安全系统都采取不同的方式,进行了对应的处理。 具体的处理细节详见下章: Chapter 3 - 实现原理 前面已经提过,目前的安全防护系统可以覆盖到8中类型的Crash,分别为: unrecognized selector crash KVO crash NSNotification crash NSTimer crash Container crash(数组越界,插nil等) NSString crash (字符串操作的crash) Bad ...
或者看看chromium for iOS的有点不一样的实现
Setting |isa| rather than using |object_setClass()| because that function is implemented with a memory barrier.

Aspect

然后是开源多年来大名鼎鼎的AspectAOP利器。

Stinger

近年来国内也有优秀的Aspect同类的开源轮子。
饿了么的Stinger
notion image

SDMagicHook

字节跳动的SDMagicHook
notion image

小结

 
无脑罗列了一堆,不求甚解,之后还是要花时间逐个研究一下,不然像字节跳动的SDMagicHook的作者未了解过Aspect就造轮子开源并发表公司文章,难免有点尴尬。
 
遗憾的是,目前为上,无论是method swizzling还是isa swizzling,都似乎没有完美互相兼容的hook方案。其他hook方案还有facebook的fishhook,以及使用汇编对objc_msgSend的hook,有待研究。

Loading Comments...