美文网首页
浅谈OC类方法load和initialize系列三

浅谈OC类方法load和initialize系列三

作者: 天蓬大元 | 来源:发表于2017-10-18 10:16 被阅读0次

    --存在继承关系时initialize和load的调用问题--

    1,如果没有重写,子类会调用父类的+(void)initialize
    示例代码一
    @interface SuperClass : NSObjec
    @end
    @implementation SuperClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    @end
    @interface ChildClass : SuperClass
    @end
    @implementation ChildClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    + (void) load {
        NSLog(@"%@ %s", [self class], __FUNCTION__);
    }
    @end
    示例代码二
    @interface SuperClass : NSObjec
    @end
    @implementation SuperClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    @end
    @interface ChildClass : SuperClass
    @end
    @implementation ChildClass
    + (void) load {
        NSLog(@"%@ %s", [self class], __FUNCTION__);
    }
    @end
    
    

    示例代码一中

    ChildClass继承自SuperClass
    SuperClass重写了initialize方法
    ChildClass重写了initialize和load方法

    示例代码二中

    ChildClass继承自SuperClass
    SuperClass重写了initialize方法
    ChildClass重写了load方法

    现在我们在Xcode的项目中只简单的import这两个类,而不去使用它们。然后运行项目,获得下面的结果:

    //示例代码一
    SuperClass +[SuperClass initialize]
    ChildClass +[SuperClass initialize]
    ChildClass +[ChildClass load]
    示例代码二
    SuperClass +[SuperClass initialize]
    ChildClass +[ChildClass initialize]
    ChildClass +[ChildClass load]
    

    根据打印结果,可以看出:
    两段代码中,打印结果完全相同。但ChildClass中并没有重写initialize方法。
    当ChildClass的load方法被运行时自动调用时,由于class方法的调用,触发initialize方法被自动调用。
    示例代码一中,ChildClass并没有重写initialize 方法,此时,由打印结果可知,先调用了父类的initialize方法,然后由于存在继承,子类没有重写父类的initialize,所以子类会去调用父类的initialize方法。
    示例代码二中,ChildClass重写了父类的initialize方法,但此时仍然会调用父类的initialize方法,然后调用子类的initialize方法。

    结论:无论子类是否重写父类的initialize方法,当子类的initialize方法被调用之前,都会先调用一次父类的initialize方法(亮点:即便被子类重写,却依然会被自动调用,这点和普通意义的继承重写规则不同)。

    注意:这种规则同样适用于继承关系不止两层的情况

    2,如果没有重写,子类不会调用父类的+(void)load
    示例代码一
    @interface SuperClass : NSObjec
    @end
    @implementation SuperClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    + (void) load {
        NSLog(@"%@ %s", [self class], __FUNCTION__);
    }
    @end
    @interface ChildClass : SuperClass
    @end
    @implementation ChildClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    @end
    示例代码二
    @interface SuperClass : NSObjec
    @end
    @implementation SuperClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    + (void) load {
        NSLog(@"%@ %s", [self class], __FUNCTION__);
    }
    @end
    @interface ChildClass : SuperClass
    @end
    @implementation ChildClass
    +(void)initialize{
        NSLog(@"%@ %s",[self class], __FUNCTION__);
    }
    + (void) load {
        NSLog(@"%@ %s", [self class], __FUNCTION__);
    }
    @end
    

    示例代码一中

    ChildClass继承自SuperClass
    SuperClass重写了initialize和load方法
    ChildClass重写了initialize方法

    示例代码二中

    ChildClass继承自SuperClass
    SuperClass重写了initialize和load方法
    ChildClass重写了initialize和load方法

    现在我们在Xcode的项目中只简单的import这两个类,而不去使用它们。然后运行项目,获得下面的结果:

    //示例代码一
    SuperClass +[SuperClass initialize]
    SuperClass +[SuperClass load]
    示例代码二
    SuperClass +[SuperClass initialize]
    SuperClass +[SuperClass load]
    ChildClass +[ChildClass initialize]
    ChildClass +[ChildClass load]
    

    根据打印结果,可以看出:
    两段代码中,打印结果完全不相同。代码区别在于ChildClass是否有重写父类的load方法。
    当父类的load方法被运行时自动调用时,由于class方法的调用,触发initialize方法被自动调用。
    示例代码一中,ChildClass并没有重写load方法,此时,由打印结果可知,子类虽然继承于父类,但此时,子类并没有去执行父类的load方法。
    示例代码二中,ChildClass重写了父类的load方法,此时运行时会调用子类重写的load方法,注意,此时并不影响父类的load方法的调用。

    结论:当子类没有重写父类的load方法,子类被引用时运行时不会自动去调用父类的load的方法,即便子类有继承父类的load方法。当子类重写了父类的load方法后,子类被引用时运行时会调用子类的load方法,此时并不会影响父类的load方法的调用。

    总结:在继承关系中,对于initialize和load方法,子类都会继承。如果父类和子类都被调用,父类的调用一定在子类之前。但:当子类的initialize方法被触发之前(不管是否重写),都会先调用父类的initialize方法,如果子类重写了initialize方法,则接下来调用子类的,如果没有重写,则接下来再次调用父类的initialize方法。而load方法则完全不同,首先,如果子类没有重写父类的load方法,则不会去调用父类的load方法,也就是说:对于一个类而言,没有load方法实现就不会调用,不会考虑对父类的继承。如果子类重写的父类的load方法,则在调用子类方法之前会自动调用父类的load方法,也就是说:一个类的load方法不用写明[super load],父类就会收到调用,并且在子类之前。

    3,不需要显示使用super调用父类中的方法

    当我们定义init方法时,我们总是需要使用super关键字来调用父类的方法,让父类也完成相同的操作。这是因为对对象的初始化过程,OC不像C++,C#那样会自动调用父类默认的构造函数。因此,我们总是需要将这个函数写成这样:

    - (id)init{
        self = [super init];
        if (self) {
        }
        return self;
    }
    

    注:ARC模式下,dealloc不用再使用super调用父类的dealloc方法
    但是initialize和load不需要使用super调用父类的方法。因为当子类的load被调用时,Runtime会自动对父类的load方法进行调用,而initialize则会随子类自动激发父类的方法,同时,当子类激活继承下来的父类方法时,如果父类的方法中用到了self,其指代的依然是子类自身,而不是父类。这是OC区别于C++,Java等面向对象语言的地方:类方法也有多态性。

    资料链接:

    [IDER]:
    http://blog.iderzheng.com
    http://blog.iderzheng.com/objective-c-load-vs-initialize/
    [MrPeak杂货铺]:http://blog.csdn.net/hanangellove/article/details/45033453
    [知乎上的一个怎么面试iOS工程师的问题]:
    http://blog.csdn.net/hanangellove/article/details/45033453

    相关文章

      网友评论

          本文标题:浅谈OC类方法load和initialize系列三

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