zoukankan      html  css  js  c++  java
  • 刨根问底:对于 self = [super init] 的思考


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

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

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

    + 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]默认调用 alloc与init方法,那么我们无法使用自定义的初始化方法,多了更多的局限性。那么[class alloc] init] 会更方便, 当然[class alloc] init] 的设计也是由于历史的原因。

    为啥这么写?

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

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

    但是对于 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对象,但super与self不同的是,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方法。
    参考文章:

    Objective-C Runtime

    http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/#objc_msgSend%E5%87%BD%E6%95%B0

    深入理解Objective-C的Runtime机制

    http://www.csdn.net/article/2015-07-06/2825133-objective-c-runtime/1

    What exactly is super in Objective-C?

    http://stackoverflow.com/questions/3095360/what-exactly-is-super-in-objective-c
  • 相关阅读:
    Hdu 5396 Expression (区间Dp)
    Lightoj 1174
    codeforces 570 D. Tree Requests (dfs)
    codeforces 570 E. Pig and Palindromes (DP)
    Hdu 5385 The path
    Hdu 5384 Danganronpa (AC自动机模板)
    Hdu 5372 Segment Game (树状数组)
    Hdu 5379 Mahjong tree (dfs + 组合数)
    Hdu 5371 Hotaru's problem (manacher+枚举)
    Face The Right Way---hdu3276(开关问题)
  • 原文地址:https://www.cnblogs.com/fengmin/p/5562707.html
Copyright © 2011-2022 走看看