Runtime列子

1.objc在向一个对象发送消息时,发生了什么?

objc在向一个对象发送消息时,runtime会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果一直到根类还没找到,转向拦截调用,走消息转发机制,一旦找到 ,就去执行它的实现IMP 。

2.objc中向一个nil对象发送消息将会发生什么?

如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。也不会崩溃。

详解:

如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil);

如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*) ,float,double,long double 或者long long的整型标量,发送给nil的消息将返回0;

如果方法返回值为结构体,发送给nil的消息将返回0。结构体中各个字段的值将都是0;

如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。

3.objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?

在objc编译时,[obj foo] 会被转意为:objc_msgSend(obj, @selector(foo));。

4.什么时候会报unrecognized selector的异常?

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果,在最顶层的父类中依然找不到相应的方法时,会进入消息转发阶段,如果消息三次转发流程仍未实现,则程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 。

5.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

不能向编译后得到的类中增加实例变量;

能向运行时创建的类中添加实例变量;

1.因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表和 instance_size 实例变量的内存大小已经确定,同时runtime会调用 class_setvarlayout 或 class_setWeaklvarLayout 来处理strong weak 引用.所以不能向存在的类中添加实例变量。 2.运行时创建的类是可以添加实例变量,调用class_addIvar函数. 但是的在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上.

6.给类添加一个属性后,在类结构体里哪些元素会发生变化

instance_size :实例的内存大小;objc_ivar_list *ivars:属性列表

7.一个objc对象的isa的指针指向什么?有什么作用?

指向他的类对象,从而可以找到对象上的方法

详解:下图很好的描述了对象,类,元类之间的关系: 

图中实线是 super_class指针,虚线是isa指针。

1.Root class (class)其实就是NSObject,NSObject是没有超类的,所以Root class(class)的superclass指向nil。 2.每个Class都有一个isa指针指向唯一的Meta class 3.Root class(meta)的superclass指向Root class(class),也就是NSObject,形成一个回路。 4.每个Meta class的isa指针都指向Root class (meta)。

9.runtime如何通过selector找到对应的IMP地址?

每一个类对象中都一个方法列表,方法列表中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现.

10._objc_msgForward函数是做什么的,直接调用它将会发生什么?

_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。

详解:_objc_msgForward在进行消息转发的过程中会涉及以下这几个方法:

List itemresolveInstanceMethod:方法 (或resolveClassMethod:)。

List itemforwardingTargetForSelector:方法

List itemmethodSignatureForSelector:方法

List itemforwardInvocation:方法

List itemdoesNotRecognizeSelector: 方法

11. runtime如何实现weak变量的自动置nil?知道SideTable吗?

runtime 对注册的类会进行布局,对于 weak 修饰的对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。

更细一点的回答:

1.初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。 2.添加引用时:objc_initWeak函数会调用objc_storeWeak() 函数, objc_storeWeak()的作用是更新指针指向,创建对应的弱引用表。 3.释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

SideTable结构体是负责管理类的引用计数表和weak表,

详解:参考自《Objective-C高级编程》一书 1.初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

当我们初始化一个weak变量时,runtime会调用 NSObject.mm中的objc_initWeak函数。

通过objc_initWeak函数初始化“附有weak修饰符的变量(obj1)”,在变量作用域结束时通过objc_destoryWeak函数释放该变量(obj1)。

2.添加引用时:objc_initWeak函数会调用objc_storeWeak() 函数, objc_storeWeak()的作用是更新指针指向,创建对应的弱引用表。

objc_initWeak函数将“附有weak修饰符的变量(obj1)”初始化为0(nil)后,会将“赋值对象”(obj)作为参数,调用objc_storeWeak函数。

也就是说:

weak 修饰的指针默认值是 nil (在Objective-C中向nil发送消息是安全的)

然后obj_destroyWeak函数将0(nil)作为参数,调用objc_storeWeak函数。

前面的源代码与下列源代码相同。

objc_storeWeak函数把第二个参数的赋值对象(obj)的内存地址作为键值,将第一个参数__weak修饰的属性变量(obj1)的内存地址注册到 weak 表中。如果第二个参数(obj)为0(nil),那么把变量(obj1)的地址从weak表中删除。

由于一个对象可同时赋值给多个附有__weak修饰符的变量中,所以对于一个键值,可注册多个变量的地址。

可以把objc_storeWeak(&a, b)理解为:objc_storeWeak(value, key),并且当key变nil,将value置nil。在b非nil时,a和b指向同一个内存地址,在b变nil时,a变nil。此时向a发送消息不会崩溃:在Objective-C中向nil发送消息是安全的。

3.释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

当weak引用指向的对象被释放时,又是如何去处理weak指针的呢?当释放对象时,其基本流程如下:

1.调用objc_release 2.因为对象的引用计数为0,所以执行dealloc 3.在dealloc中,调用了_objc_rootDealloc函数 4.在_objc_rootDealloc中,调用了object_dispose函数 5.调用objc_destructInstance 6.最后调用objc_clear_deallocating

对象被释放时调用的objc_clear_deallocating函数:

1.从weak表中获取废弃对象的地址为键值的记录 2.将包含在记录中的所有附有 weak修饰符变量的地址,赋值为nil 3.将weak表中该记录删除 4.从引用计数表中删除废弃对象的地址为键值的记录

总结:

其实Weak表是一个hash(哈希)表,Key是weak所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。

13.使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

无论在MRC下还是ARC下均不需要,被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被 NSObject -dealloc 调用的object_dispose()方法中释放。

详解:

1、调用 -release :引用计数变为零

对象正在被销毁,生命周期即将结束.

不能再有新的 __weak 弱引用,否则将指向 nil.

调用 [self dealloc]

2、 父类调用 -dealloc

继承关系中最直接继承的父类再调用 -dealloc

如果是 MRC 代码 则会手动释放实例变量们(iVars)

继承关系中每一层的父类 都再调用 -dealloc

>3、NSObject 调 -dealloc

只做一件事:调用 Objective-C runtime 中object_dispose() 方法

>4. 调用 object_dispose()

为 C++ 的实例变量们(iVars)调用 destructors

为 ARC 状态下的 实例变量们(iVars) 调用 -release

解除所有使用 runtime Associate方法关联的对象

解除所有 __weak 引用

调用 free()

14. 什么是method swizzling(俗称黑魔法)

简单说就是进行方法交换

在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法挂钩的目的。 每个类都有一个方法列表,存放着方法的名字和方法实现的映射关系,selector的本质其实就是方法名,IMP有点类似函数指针,指向具体的Method实现,通过selector就可以找到对应的IMP。 换方法的几种实现方式

利用 method_exchangeImplementations 交换两个方法的实现

利用 class_replaceMethod替换方法的实现

利用 method_setImplementation 来直接设置某个方法的IMP 

15.CompileError / Runtime Crash / NSLog…?

下面的代码会?Compile Error / Runtime Crash / NSLog…?

IMP: -[NSObject(Sark) foo] ,全都正常输出,编译和运行都没有问题。

详解:

这道题和上一道题很相似,第二个调用肯定没有问题,第一个调用后会从元类中查找方法,然而方法并不在元类中,所以找元类的superclass。方法定义在是NSObject的Category,由于NSObject的对象模型比较特殊,元类的superclass是类对象,所以从类对象中找到了方法并调用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容