美文网首页
Objective-C中的Runtime(四) 面试题

Objective-C中的Runtime(四) 面试题

作者: 暗物质 | 来源:发表于2019-10-19 22:09 被阅读0次

说说什么是runtime

OC 是一个全动态语言,OC 的一切都是基于 Runtime 实现的
平时编写的OC代码, 在程序运行过程中, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者,比如:

OC :
[[Person alloc] init]
runtime :
objc_msgSend(objc_msgSend("Person" , "alloc"), "init")

runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
runtimeAPI的实现是用 C++ 开发的(源码中的实现文件都是mm),是一套苹果开源的框架。

使用过runtime吗,用它来做什么

上几篇文章的应用部分。
发送消息、交换方法、类\对象的关联对象、动态添加方法、配合KVC字典自动转模型、自动归档解档。

runtime的方法调用流程?

如果用实例对象调用实例方法,会到实例的isa指针指向的对象(也就是类对象)操作。
如果调用的是类方法,就会到类对象的isa指针指向的对象(也就是元类对象)中操作。

--> 1.首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。

--> 2.如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现并执行。

--> 3.如果没找到,去父类指针所指向的对象中执行1,2。

--> 4.依次类推,如果一直到根类还没找到,转向拦截调用。

--> 5.如果没有重写拦截调用的方法,程序报错。

Category和Extension的区别

1、Extension在编译期决议,它就是类的一部分,在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。Extension一般用来隐藏类的私有信息,你必须有一个类才能为这个类添加Extension,所以你无法为系统的类比如NSString添加Extension。
2、Category则完全不一样,它是在运行期决议的。
3、Extension可以添加属性、成员变量,而Category一般不可以。
总之,就Category和Extension的区别来看,Extension可以添加实例变量,而Category是无法添加实例变量的。因为Category在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的。

为什么Category中不能动态添加成员变量?

在runtime函数中,确实有一个class_addIvar()函数用于给类添加成员变量,但是阅读过苹果的官方文档的人应该会看到:

This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.

大概的意思说,这个函数只能在“构建一个类的过程中”调用。一旦完成类定义,就不能再添加成员变量了。经过编译的类在程序启动后就被runtime加载,没有机会调用addIvar。程序在运行时动态构建的类需要在调用objc_registerClassPair之后才可以被使用,同样没有机会再添加成员变量。

为什么不能为一个类动态的添加成员变量,可以给类动态增加方法和属性?

因为方法和属性并不“属于”类实例,而成员变量“属于”类实例。我们所说的“类实例”概念,指的是一块内存区域,包含了isa指针和所有的成员变量。所以假如允许动态修改类成员变量布局,已经创建出的类实例就不符合类定义了,变成了无效对象。但方法定义是在objc_class中管理的,不管如何增删类方法,都不影响类实例的内存布局,已经创建出的类实例仍然可正常使用。

相关文章

网友评论

      本文标题:Objective-C中的Runtime(四) 面试题

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