iOS之runtime小结

321 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

什么是runtime?

runtime 一套C、C++、汇编编写的API,为OC提供运行时功能。能够将数据类型的确定由编译期推迟到运行时。 问题?方法的本质?或runtime的消息机制? 方法的本质就是消息发送 发送消息的主要流程:

  • 1.快速查找:objc_msgSend查找cache_t缓存消息
  • 2.慢速查找:递归自己和父类查找方法lookUpImpOrForworw
  • 3.查找不到消息,进行动态方法解析:resolveInstanceMethod
  • 4.消息快速转发:forwardingTargetForSelector
  • 5.消息慢速转发:消息签名methodSignatureForSelector和分发forwardinvocation
  • 6.最终仍未找到消息:程序crash,报经典错误unrecognized selector sent to instance XXX SEL是什么?IMP是什么?两者有什么联系?
  • SEL是方法编号,即方法名称,在dyld加载镜像时,通过read_image方法加载到内存的表中了。
  • IMP时函数实现指针,找IMP就是找函数的过程
  • 两者的关系:sel相当于书本的目录标题,imp就是书本的页码。查找具体的函数就是想看这本书里面具体篇章的内容:
    • 1.我们首先知道想看什么,也就是title -sel
    • 2.然后根据目录对应的页码 -imp
    • 3.打开具体的内容 -方法的具体实现

runtime应用

    1. 方法的交换:具体应用拦截系统自带的方法调用(Method Swizzling黑魔法)
  • 2.实现给分类增加属性
  • 3.实现字典的模型和自动转换
  • 4.JSPatch替换已有的OC方法实现等
  • 5.aspect切面编程 能否向编译得到的泪中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
  • 1.不能向编译后得到的类中增加实例变量。
  • 2.可以向运行时创建的类中添加实例变量。
  • 3.因为编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,同时runtime会调用class_setIvarLayoutclass_setWeakIvarLayout来处理strongweak引用,所以不能向存在的类中添加实例变量。运行时创建的类是可以添加实例变量,调用class_addIvar函数。但是得在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上。 Category中添加属性和成员变量的区别
  • 1.Category它的主要作用是在不改变原有类的前提下,动态的给这个类添加一些方法。
  • 2.分类的结构体指针中,没有属性列表,只有方法列表。原则上它只能添加方法,不能添加属性(成员变量),但是可以借助运行时关联对象objc_setAssociatedObject(self,@selector(name),name,OBJC_ASSOCIATION_COPY_NONATOMIC);objc_getAssociatedObject(self,@selector(name));.
  • 3.分类中可以写@property,但不会生成setter/getter方法声明和实现,也不会生成私有的成员变量,会编译通过,但是引用变量会报错。
  • 4.如果分类中有和原有类同名的方法,会优先调用分类中的方法,就是说会忽略原有类的方法,同名方法调用的优先级为 分类 本类 父类,因为方法是放在方法栈中,遵循先进后出原则。