关于runtime,在调用方法的时候,编译器会根据情况在
objc_msgSend
,objc_msgSend_stret
,objc_msgSendSuper
,objc_msgSendSuper_stret
,objc_msgSend_fpret
五个方法中选择一个来调用。
· 消息传递给超类,会调用objc_msgSendSuper
方法;
· 消息返回值是数据结构,会调用objc_msgSendSuper_stret
方法;
· 返回值是浮点数,则调用objc_msgSend_fpret
方法。
在message.h中,objc_msgSend
、objc_msgSendSuper
方法的声明:
以下使用到的是第二种编译方式(就是
else
里面的)。当我们调用
[super selector]
时,Runtime会调用objc_msgSendSuper
方法,objc_msgSendSuper
方法有两个参数,super
和op
,Runtime会把selector方法选择器
赋值给op
。而super
是一个__rw_objc_super结构体指针
,__rw_objc_super
结构体定义如下:
Runtime会创建一个__rw_objc_super
结构体变量,将其地址作为参数(super)传递给objc_msgSendSuper
,而且将self赋值给receiver:super->receiver=self
事例代码说明(Son父类为Father):
使用clang命令,上述代码被转化为: 这里讨论self和super的问题,所以以下只看两个NSLog方法,如下对两个NSLog转化后的代码,进行了删减,以便对比
msgSend
和msgSendSuper
注意被框框框住的部分。在__rw_objc_super结构体中,
第一个成员变量:是当前的self指针(在下面事例中是Son); 第二个成员变量:根据Son获取它的父类
关于
objc_msgSendSuper
中的几个参数的大致说明(来源于注释部分,上面message.h代码截图部分,可以对号入座)super是一个objc_super
类型的结构体,在消息发送过程中,传递一些环境变量值。这些值包括:接收消息的类的实例对象(意思就是这个对象就是[super class]
的调用者),以及这个实例对象的父类,这个父类将用于寻找class
方法的具体实现。
总结:
在执行[super message]时,会做的事情:
1.编译器会先构造一个__rw_objc_super
结构体
2.然后去superClass的方法列表
中找方法
3.找到后由object
调用.
初始化方法中为什么要写self = [super init]?
这和类簇有关系,我们不能保证init的内存和alloc出来的内存是同一块内存,像NSString在alloc和init之后的对象分别是NSPlaceholderString和__NSCFConstantString*造成[super init]之后的内存被改变,所以在[super init]之后是nil,因此我们不能保证alloc和init的是同一块内存,加上这样的判断是为了提高容错性,如果init成功就返回对象,否则返回nil。self指向了父类初始化的内存地址。类的初始化函数如果失败会返回nil,随后self也为nil。 if(self = nil),你往下的初始化工作都是对nil做的,初始化失败。
父类进行初始化时,用的是子类对象指针self,父类的init方法有可能对这个指针指向的内存区作了大的变更(有可能把这个指针所指的内存释放了,重新分配了另一块内存区域返回来,这时这个返回的指针与原来的指针是指向不同地址的),所以父类初始化后要重新返回指针。父类返回的和子类的self的类型都为id类型(通用类型)。父类的init方法若返回的指针与self不一样,在父类的init方法中已作了release和新的内存分配,不需要自己再去release self,直接用父类init方法返回的指针就可以了。
相关学习文章:
ios开发self和super的区别
Runtime的理解与实践
iOS 调用IMP/objc_msgSend详细说明
Objective-C语言的if(self=[super init])什么意思?
网友评论