iOS中的Runtime

一.isa

isa的理解

  • 在arm64架构之前, isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
  • 从arm64架构开始,对isa进行了优化,变成了一个共用体( union )结构,还使用位域来存储更多的信息

使用64位(8个字节)存储了大量信息

源码---右方数字表示占用的位数
union isa_ t
{
    Class cls;
    uintptr_ ,t bits;
    struct (
        uintptr_ t nonpointer          : 1;
        uintptr_t has_assoc:           : 1;
        uintptr_t has_cxX_ dtor        : 1;
        uintptr_t shiftcls             : 33;
        uintptr_t magic                : 6;
        uintptr_t weakly_referenced    : 1;
        uintptr_t deallocating         : 1;
        uintptr_t has_sidetable_ rc    : 1;
        uintptr_t extra_rc             : 19;
    );
};

注意:shiftcls保存着类对象的地址值,占用33bit

位运算---设值与取值
取值用按位与& (0b0000 0001-取第八位数值)
设值用按位与&(0b1111 1110-设第八位为0) + 按位或|(0b0000 0001-设第八位为1):需要确保其他值不变,只修改想设置的值
(按位非 ~)

图片.png

二.class结构

图片.png

图片.png

图片.png

cache缓存

图片.png

Class内部结构中有个方法缓存( cache_t ) , 用散列表来缓存曾经调用过的方法,可以提高方法的查找速度(空间换时间
图片.png

SEL --函数(方法)名
imp --指向函数的指针(函数地址)

用下面一张图大概概括class的结构


2531642047642_.pic_hd.jpg

三.objc_msgSend 消息转发

OC的方法调用:消息机制,给方法调用者发送消息
objc_msgsend的执行流程可以分为3大阶段
- 消息发送

图片.png

- 动态方法解析
两个关键实现方法:+resolveInstanceMethod:/+resolveClassMethod:

图片.png

在OC中调用某个方法,当第一步,消息发送阶段未找到此方法时,会进入第二步---动态方法解析

//动态添加实例方法
- (void)other
{
    NSLog(@"%s",__ func__ );
}
+ ( BOOL)resolveInstanceMethod: (SEL )sel
{
        if(sel == @selector(test)) f
        // 获取其他方法
        Method method = class_ getInstanceMethod(self, @selector(other));
        //动态添加test方法的突現
        class_addMethod(self, sel,
            method_getImplementation(method) ,
            method_getTypeEncoding(method));
        //返回YES代表有幼恋添加方法
        return YES;
}
    return [super resolveInstanceMethod:sel];
}

- 消息转发
当方法调用的第一步,与第二步都没有调用成功的时候。会进入第三步--消息转发,执行方法 forwardingTargetForSelector

//当进入第三步时,会调用 MJCat 的test方法
- (id)forwardingTargetForSelector: (SEL)aSelector{
       if (aSelector == @selector(test)) f
          return [[MJCat alloc] init];
       }
       return [super forwardingTargetForSelector :aSelector];
}
图片.png

扩展

提醒编译器不要自动生成setter和getter的实现、不要自动生成成员变量
@dynamic age;

四.[ self class]与[super class]

一.[ self class]的底层实现

  • 1.objc_msgSend消息接收者仍然是子类对象
    所以super class与self class 本质是一样的
-(Class) class{
   return object_ getClass(self );
}
  • 2.从父类开始查找方法的实现

二.[self superclass]的底层实现
superclass方法的返回值,也是取决于消息接收(调用)者是谁

- (Class) superclass //获取调用者的父类
{
  return class_getSuperclass(object_getClass(self)); //获取self对象的父类方法
}

因此 [self superclass]与[super superclass]的本质一样

同一个类中,下面两个方法的打印结果是一样的

NSLog(@"[self class] = %@", [self class]);
NSLog(@"'[ super class]= %@"[super class]);
NSLog (@"[ self superclass] = %@", [self superclass]) ;
NSLog (@"[ super superclass] = %@", [super superclass]) ;

五.isKindOfClass和isMemberOfClass

实例方法
-(BOOL)isKindOfClass:(Class)aClass;// 判断左边实例的类对象或其父类的类对象是否跟右边类对象相等
-(BOOL)isMemberOfClass:(Class)aClass; // 判断左边实例的类对象是否跟右边类对象相等

类方法
+(BOOL)isKindOfClass:(Class)aClass;//左边类的类对象父类的类对象(即元类)是否跟右边类对象相等
+(BOOL)isMemberOfClass:(Class)aClass;//左边类的类对象(即元类)是否跟右边类对象相等

六.面试题

一.讲一下OC的消息机制

  1. OC中的方法调用其实都是转成了objc msgSend函数的调用,给receiver (方法调用者)发送了一条消息 ( selector方法名)

2.objc_ msgSend底层有3大阶段
消息发送(当前类、父类中查找)、动态方法解析、消息转发

二.什么是Runtime?平时项目中有用到过吗?
OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行
OC的动态性就是由Runtime来支撑和实现的, Runtime是一 套C语言的API ,封装了很多动态性相关的函数
使用:
1.类相关: 利用关联对象,给分类添加属性(成员变量)
2.成员变量:遍历类的所有成员变量(修改textfield的占位文字颜色(修改成员变量值)、字典转模型(YYmodel的核心)、自动归档解档)
3.方法相关
1.方法交换(hook(钩子)方法,最常用的应用是防止数组、字典等越界崩溃).
2.利用消息发送机制进行非常规的方法调用 objc_msgSend

方法交换实例:

+ (void)swizzleInstanceMethod2:(SEL)originalSel with:(SEL)swizzledSel {
    Method originalMethod = class_getInstanceMethod(self, originalSel);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);

    NSLog(@"给当前分类添加原类的方法originalSelector");
    BOOL didAddMethod =
    class_addMethod(self,
                    originalSel,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));
    
    if (didAddMethod) {
        NSLog(@"originalSelector方法在原类中不存在,已经添加成功,用下面的方法替换其实现");
        class_replaceMethod(self,
                            swizzledSel,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        NSLog(@"如果原类中已存在originalSelector的话,那么添加失败而已,返回NO");
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

方法交换代码解析
方法交换应用场景//统计用户进入各个控制器的次数

  • Runtime中相关的API
//动态创建-一个类(参数:父类,类名,额外的内存空间)
Class objc_allocateClassPair(Class superclass, const char *name, size_ _t extraBytes)
//注册一个类(要在类注册之前添加成员变量)
void objc_registerClassPair(Class cls)
//销毁一个类
void objc_disposeClassPair(Class cls)
//获取isa指向的Class
Class object_getClass(id obj)
//设置isa指向的Class
Class object_setClass(id obj, Class cls)
//判断一个OC对象是否为Class
BOOL object_isClass(id obj)
//判断一个Class是否为元类
BO0L class_isMetaClass(Class cls) 
//获取父类
Class class_getSuperclass(Class cls)
  • Runtime中成员变量相关的API
//获取一个实例变量
Ivar class_getInstanceVariable(Class cls, const char *name)

//拷贝实例变量列表(最后需要调用free释放)
Ivar *Class_copyIvarList(Class cls, unsigned int *outCount)

//设置和获取成员变量的值
void object_setIvar(id obj, Ivar ivar, id value)
id object_getIvar(id obj, Ivar ivar)

//动态添加成员变量(已经注册的类是不能动态添加成员变量的)
BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

//获取成员变量的相关信息
const char *ivar_getName(Ivar v)
const char *ivar_getTypeEncoding(Ivar v)
  • Runtime中方法相关的API
//获得一个实例方法、类方法
Method class_ getInstanceMethod(Class cls, SEL name)
Method class_ _getClassMethod(Class cls, SEL name)
//方法实现相关操作
IMP class_ getMethodImplementation(Class cls, SEL name)
IMP method_ set Imp lementation (Method m, IMP imp)
void method_ exchangeImp lementat ions (Method m1, Method m2)
//拷贝方法列表(最后需要凋用free釋放)
Method *Class_ copyMethodList(Class cls, unsigned int *outCount)
//动态添加方法
B00L class_ addMethod(Class cls, SEL name, IMP imp, const char *types)
//动态替換方法
IMP class_ replaceMethod(Class cls, SEL name, IMP imp, const char *types)
//获取方法的相关信息(帯有copy的需要凋用free去釋放)
SEL method_ getName (Method m)
IMP method_ getImplementation(Method m)
const char *method_getTypeEncoding (Method m)
unsigned int method_getNumberOfArguments (Method m)
char *method_copyReturnType (Method m)
char *method_copyArgumentType(Method m, unsigned int index)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容