runtime之类方法和实例方法

在本文开始之前,先发表下个人见解。runtime是OC语言的特性,Method
Swizzling 是苹果针对runtime暴露的API接口。如果,你使用Method
Swizzling造成了一些的问题,那可能是你使用Method Swizzing
的姿势有些不太对。下一篇文章会对Method Swizzing 造成的问题,
以及为什么会造成这些问题做一个总结。下面先来说说本文标题的内容。
什么是类方法和实例方法?
1.从标识符角度考虑
在Objective-C中标识符 "-" 是实例方法,标识符"+"是类方法/静态方法。
2.从调用方式上考虑
实例方法的调用时需要实例对象,而类方法的调用则可以通过类直接调
用。
在runtime中

isa 指针指向
实例对象的isa指针指向该实例对象的类,类指向该类元类,元类有点特殊,统一指向根元类,根元类指向自己。
继承关系
类继承自己的父类,继承体系一直往上,最终指向nil,元类指向父元类,最终根元类,指向NSObject。
内存分配
指向实例化对象的指针,存储在栈区;实例化的Objective-C对象存储在堆区,类和元类存在在代码段。
实例方法的调用
对象方法的调用实际上是发送消息给这个对象,对象在接受到这个消息之后。首先,他会去方法缓存列表中根据SEL查找函数指针IMP,找到之后直接通过指针调用该函数。如果,没有找到就去方法列表methodlist中根据SEL查找函数指针IMP。找到后直接通过指针调用函数,并且把该方法放在缓存列表中,如果没找到那就沿着继承体系向上查找。如果,还是找不到该方法,那就执行消息转发。
类方法调用
首先我们知道类方法是保存在该类的元类中的,类在OC中,也可以看成是元类的一个实例。当类方法被调用的时候,元类首先会查找本身是否有该类方法的实现,如果没有该元类会向他的父元类继续查找该方法,一直找到继承链的头。类方法不会出现向实例方法找不到的情况。因为,如果不存在该类方法,那么在编译的时候都通不过。
关于实例方法和类方法的内存占用
实例方法
实例对象的创建被分配在堆区,该对象的内存管理完全交给了ARC去完成。实例方法只有在调用的时候才会分配内存,这个点可以通过Xcode自带的Instruments工具中Allocations来做测试,证明想法,楼主这里就不做演示。
类方法
类方法的调用不同于实例方法,下面来看一张图:

一个类可以有n个实例化对象,但是一个元类只有一个类实例,这个类的isa唯一指向元类。当App在启动的时候就已经为类方法分配了内存,而且贯穿整个app应用的生命周期。类方法的调用会常驻内存,不是被调用才会常驻内存,而是一直都会。