美文网首页
关于Runtime

关于Runtime

作者: 未_漆小七 | 来源:发表于2018-01-16 16:46 被阅读0次

一个objc对象如何进行内存布局?(考虑有父类的情况)

NSString *str = @“”;

* 所有父类的成员变量和自己的成员变量都会存放在该对象str所对应的存储空间中.

* 每一个对象内部都有一个isa指针,指向他的类对象NSString,类对象中存放着本对象的

* 对象方法列表(对象能够接收的消息列表,保存在它所对应的类对象中)

* 成员变量的列表,

* 属性列表,

* 它内部也有一个isa指针指向元对象(meta class),(既类对象所属的类型,用来表述NSString 是一个什么样的对象 元对象内部存放的是类方法列表)

* 类对象内部还有一个superclass的指针,指向他的父类对象。

* NSObject,它的superclass指针指向nil

* 类对象既然称为对象,那它也是一个实例。类对象中也有一个isa指针指向它的元类(meta class),即类对象是元类的实例。元类内部存放的是类方法列表,根元类的isa指针指向自己,superclass指针指向NSObject类。

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

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

objc中的类方法和实例方法有什么本质区别和联系?

类方法:

1. 类方法是属于类对象的

2. 类方法只能通过类对象调用

3. 类方法中的self是类对象

4. 类方法可以调用其他的类方法

5. 类方法中不能访问成员变量

6. 类方法中不能直接调用对象方法

实例方法:

1. 实例方法是属于实例对象的

2. 实例方法只能通过实例对象调用

3. 实例方法中的self是实例对象

4. 实例方法中可以访问成员变量

5. 实例方法中直接调用实例方法

6. 实例方法中也可以调用类方法(通过类名)

runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和实例方法)?

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

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

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。

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

objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。

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

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

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果,在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 。但是在这之前,objc的运行时会给出三次拯救程序崩溃的机会:

1. Method resolutionobjc运行时会调用+resolveInstanceMethod:或者 +resolveClassMethod:,让你有机会提供一个函数实现。如果你添加了函数,那运行时系统就会重新启动一次消息发送的过程,否则 ,运行时就会移到下一步,消息转发(Message Forwarding)。

2. Fast forwarding如果目标对象实现了-forwardingTargetForSelector:,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会。既能不能把这条消息转发给其他接受者处理, 只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,当然发送的对象会变成你返回的那个对象。否则,就会继续Normal Fowarding。 这里叫Fast,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但下一步转发会创建一个NSInvocation对象,所以相对更快点。

3. Normal forwarding这一步是Runtime最后一次给你挽救的机会。首先它会发送-methodSignatureForSelector:消息获得函数的参数和返回值类型。如果-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象。

下面的代码输出什么?

@implementation Son : Father

- (id)init

{

self = [super init];

if (self) {

NSLog(@"%@", NSStringFromClass([self class]));

NSLog(@"%@", NSStringFromClass([super class]));

}

return self;

}

@end

其实 super 是一个 Magic Keyword, 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者!他们两个的不同点在于:super 会告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。

上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *xxx 这个对象。

当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。

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

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

结合《NSObject官方文档》,排除掉 NSObject 做的事,剩下的就是_objc_msgForward消息转发做的几件事:

1. 调用resolveInstanceMethod:方法 (或 resolveClassMethod:)。允许用户在此时为该 Class 动态添加实现。如果有实现了,则调用并返回YES,那么重新开始objc_msgSend流程。这一次对象会响应这个选择器,一般是因为它已经调用过class_addMethod。如果仍没实现,继续下面的动作。

2. 调用forwardingTargetForSelector:方法,尝试找到一个能响应该消息的对象。如果获取到,则直接把消息转发给它,返回非 nil 对象。否则返回 nil ,继续下面的动作。注意,这里不要返回 self ,否则会形成死循环。

3. 调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation:。

4. 调用forwardInvocation:方法,将第3步获取到的方法签名包装成 Invocation 传入,如何处理就在这里面了,并返回非ni。

5. 调用doesNotRecognizeSelector: ,默认的实现是抛出异常。如果第3步没能获得一个方法签名,执行该步骤。

一旦调用_objc_msgForward,将跳过查找 IMP 的过程,直接触发“消息转发”,

如果调用了_objc_msgForward,即使这个对象确实已经实现了这个方法,你也会告诉objc_msgSend:“我没有在这个对象里找到这个方法的实现”

有哪些场景需要直接调用_objc_msgForward?最常见的场景是:你想获取某方法所对应的NSInvocation对象。举例说明:

JSPatch (Github 链接)就是直接调用_objc_msgForward来实现其核心功能的:

JSPatch 以小巧的体积做到了让JS调用/替换任意OC方法,让iOS APP具备热更新的能力。

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

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

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

解释下:

* 因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表 和 instance_size 实例变量的内存大小已经确定,同时runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量;

* 运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。

http://www.jianshu.com/p/e071206103a4 runtime 的使用场景

相关文章

  • swift runtime

    关于 runtime

  • iOS中Runtime的常用方法

    Runtime是什么? Apple关于Runtime的详细文档链接:Runtime Guide其实大家对Runti...

  • Learn Runtime

    Runtime 参考资料: RunTime应用实例--关于埋点的思考 使用Runtime进行埋点操作-Demo...

  • Golang中runtime的使用

    Golang中runtime的使用 runtime调度器是非常有用的东西,关于runtime包几个方法: Gosc...

  • iOS-Runtime

    一.什么是runtime? 话说每次面试都问runtime,你不会runtime能拿到像我66k的工资吗?所以关于...

  • 使用反射重构代码(OC)

    前沿 OC里的runtime就是Java里反射的概念。关于OC中runtime的应用早就被玩烂了, 今天介绍关于用...

  • 关于Runtime

    lldb(gdb)常用的调试命令? po:打印对象,会调用对象description方法。是print-objec...

  • 关于Runtime

    一个objc对象如何进行内存布局?(考虑有父类的情况) NSString *str = @“”;* 所有父类的成员...

  • 关于runtime

    一、runtime简介 RunTime简称运行时。OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消...

  • 关于runtime

    runtime:一个程序在运行(或者在被执行)的状态。也就是说,当你打开一个程序使它在电脑上运行的时候,那个程序就...

网友评论

      本文标题:关于Runtime

      本文链接:https://www.haomeiwen.com/subject/scuowxtx.html