美文网首页原理iOS Blogios基础知识
刨根问底:对于 self = [super init] 的思考

刨根问底:对于 self = [super init] 的思考

作者: Joy___ | 来源:发表于2016-03-25 12:54 被阅读4639次

对象初始化有两种方式:[class new][[class alloc] init]

对于后者,有分配和初始化的过程,alloc 从应用程序的虚拟地址空间上为该对象分配足够的内存,并且将新对象的引用计数加1、将对象的成员变量初始为零,init 会做真正的初使化工作,为对象的实例变量赋予合理有用的值。

一般不推荐使用[class new],而推荐使用[[class alloc] init],查看源码分析一下:

+ new 
{ 
    id newObject = (*_alloc)((Class)self, 0); 
    Class metaClass = self->isa; 
    if (class_getVersion(metaClass) > 1) 
    return [newObject init]; 
    else 
    return newObject; 
} 
 
//而 alloc/init 像这样: 
+ alloc 
{ 
    return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  
} 
- init 
{ 
    return self; 
} 

发现[class new]默认调用 allocinit方法,那么我们无法使用自定义的初始化方法,多了更多的局限性。那么[class alloc] init] 会更方便, 当然[class alloc] init] 的设计也是由于历史的原因。

为啥这么写?

- (instancetype)init
{
    if (self = [super init]) {
        // Custom initialization
    }
    return self;
}

我们知道alloc返回一个有效的未初始化的对象实例。对于selfalloc 返回的指针,同时可以在所有的方法作用域内访问。

但是对于 super,它只是一个"编译器指示符",告诉编译器在父类中搜索方法的实现。

优先调用[super init] 是为了使超类完成它们自己的初始化工作。

那么 if (self = [super init])又是做啥?

这里是担心父类初始化失败,如果初始化一个对象失败,就会返回nil,当返回nil的时候self = [super init]测试的主体就不会再继续执行。如果不这样做,你可能会操作一个不可用的对象,它的行为是不可预测的,最终可能会导致你的程序崩溃。

理解 Self & Super

看到网上一道经典的题目:

@implementation Son : Father
- (id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end

self表示当前这个类的对象,而super是一个编译器标示符,和self指向同一个消息接受者。在本例中,无论是[self class]还是[super class],接受消息者都是Son对象,但superself不同的是,self调用class方法时,是在子类Son中查找方法,而super调用class方法时,是在父类Father中查找方法。

当调用[self class]方法时,会转化为objc_msgSend函数,这个函数定义如下:

id objc_msgSend(id self, SEL op, ...)  

这时候就开始了消息传递和转发的过程,会先从Cache 中查找方法,然后当前类,如果还是查找不到会去父类,直至NSObject

对于NSObject类中,- (Class)class的实现如下:

- (Class)class {  
    return object_getClass(self);  
}  

所以打印结果为Son

当调用[super class]方法时,会转化为objc_msgSendSuper,这个函数定义如下:

id objc_msgSendSuper(struct objc_super *super, SEL op, ...)  

objc_msgSendSuper函数第一个参数super的数据类型是一个指向objc_super的结构体

struct objc_super {
   __unsafe_unretained id receiver;
   __unsafe_unretained Class super_class;
};

结构体包含两个成员,第一个是receiver,表示类的实例。第二个成员是记录当前类的父类是什么,会优先从Father这个类里去找- (Class)class,然后进行消息传递的过程。

会发现不管是self、还是super指向消息接受者是一样的,并且经过消息传递,最终处理消息的方法都是NSObject中的- (Class)class方法。

参考文章:

相关文章

网友评论

  • 小如99:写的挺好的,LZ的源码是怎么生成的了?我运行runtime只会得到
    NSString *object = ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("new"));
    NSString *objectInit = ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("alloc")), sel_registerName("init"));
    这样的代码
  • WilsonW:插圖要改進
    太容易分神了
    看著看著就忘討論主題了 哈哈
    Joy___:@WilsonW :joy:
  • e6f6d7b458be:学习 受教啦
  • xzZZzx:博主,有个地方有点问题,对象alloc之后其实不止是在虚拟内存上分配空间的,物理内存上也会有映射的
    Joy___:@xzZZzx 学习 :smile:
  • zczb:请问self是alloc返回的指针,还是init返回的指针?看代码是init返回的啊...
  • 2e93b06e9594:请教:_alloc方法前面带个星号是什么意思?
    Joy___:@2e93b06e9594 函数指针 :wink:
  • 650388206d5c:@Martin_wjl 会发现不管是self、还是super指向消息接受者是一样的,并且经过消息传递,最终处理消息的方法都是NSObject中的- (Class)class方法:return object_getClass(self);
    既然最后调用的都是NSObject的方法,self又是同一个,那最后为什么结果能会是不一样?系统怎么区分的?
    Joy___:@小楷1987 结果都是son
  • 小笨狼:New: This method is a combination of alloc and init. Like alloc, it initializes the isa instance variable of the new object so it points to the class data structure. It then invokes the init method to complete the initialization process.
    小笨狼:@Martin_wjl 不好意思,我没仔细看源码,误会了 :joy:
    Joy___:@小笨狼 :smile: 代码应该出自GNUstep吧,我刚才去找了一下,代码太多了,我也么有找到new的代码,然后写的时候主要是参照了国内外的一些博客,源代码表示和apple文档一致呀,new代表着alloc和init一起调用,可能是我博客表述有些词语没提到。。。如果您找到了可以提示一下 :stuck_out_tongue_closed_eyes:
    小笨狼:@小笨狼 博主的源码有出处么?apple的官方文档是new代表着alloc和init一起调用
  • youngyunxing:写的不错,赞
  • 794f64d7a292:啊哈,这块是重点也是比较绕的难点,不错

本文标题:刨根问底:对于 self = [super init] 的思考

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