美文网首页
OC基础-category(3)

OC基础-category(3)

作者: 我是卖报的小行家 | 来源:发表于2021-03-05 09:34 被阅读0次

    initialize方法

    initialize方法被调用的时机:
    initialize方法会在 “类” 在第一次 “接收到消息” 时候被调用([MJPerson alloc],这个就是MJPerson这个类在第一次接收到消息的时候)(消息分发机制)
    验证:
    先创建MJPerson类,以及其分类

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MJPerson : NSObject
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "MJPerson.h"
    
    @implementation MJPerson
    + (void)initialize
    {
        NSLog(@"MJPerson initialize");
    }
    @end
    

    分类1 MJPerson + Test1

    #import "MJPerson.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MJPerson (Test1)
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "MJPerson+Test1.h"
    
    @implementation MJPerson (Test1)
    + (void)initialize
    {
        NSLog(@"MJPerson (Test1) initialize");
    }
    @end
    

    分类2 MJPerson + Test2

    #import "MJPerson.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MJPerson (Test2)
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "MJPerson+Test2.h"
    
    @implementation MJPerson (Test2)
    + (void)initialize
    {
        NSLog(@"MJPerson (Test2) initialize");
    }
    @end
    
    1).如果我们从不用到MJPerson这个类,则永远不会调用initialize这个方法,这点是和load方法的一个最大区别之一
    2).哪怕我们多次调用alloc ,则只输出一次,因为initialize方法会在 “类” 在第一次 “接收到消息” 时候被调用
    
        [MJPerson alloc];//MJPerson第一次接收消息
        [MJPerson alloc];
        [MJPerson alloc];
        [MJPerson alloc];
    
    打印结果,且顺序是与编译顺序有关,先编译后调用
    

    2021-03-04 17:16:45.905523+0800 Test[6043:989433] MJPerson (Test1) initialize

    ![打印结果](https://img.haomeiwen.com/i17524917/ab2b127a28de4fff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    调用顺序:
    如果是子类调用alloc方法,则会先调用父类的initialize方法,然后再调用自己的或者自己分类的initialize方法
    
    
        [MJStudent alloc];//MJPerson第一次接收消息
        [MJStudent alloc];
        [MJStudent alloc];
        [MJStudent alloc];
    

    打印结果

    2021-03-04 17:23:45.626093+0800 Test[6179:995502] MJPerson (Test1) initialize
    2021-03-04 17:23:45.626133+0800 Test[6179:995502] MJStudent (Test2) + initialize

    因为[MJPerson alloc]和[Person test]本质上就是objc_msgSend([Person class], @selector(alloc))消息发送。所以猜测应该是在objc_msgSend()方法中调用了initialize方法,并且只是在类第一次收到msg消息的时候调用一次,以后就不再调用了。而且initialize方法跟load方法不一样,不是通过指针去调用的,而是通过objc_msgSend()去调用的,这一点可以从源码可知。
    

    void _class_initialize(Class cls)
    {
    assert(!cls->isMetaClass());

    Class supercls;
    bool reallyInitialize = NO;
    
    // Make sure super is done initializing BEFORE beginning to initialize cls.
    // See note about deadlock above.
    supercls = cls->superclass;
    

    //先判断父类有没有初始化,如果没有就初始化父类
    if (supercls && !supercls->isInitialized()) {
    _class_initialize(supercls);
    }

    // Try to atomically set CLS_INITIALIZING.
    {
        monitor_locker_t lock(classInitLock);
    

    //再判断自身是否初始化,如果没有就初始化一下
    if (!cls->isInitialized() && !cls->isInitializing()) {
    cls->setInitializing();
    reallyInitialize = YES;
    }
    }

        源码伪代码
        if(自己没有初始化){
            if (父类没有初始化) {
                objc_msgSend([Person class], @selector(alloc))
            }
            objc_msgSend([Student class], @selector(alloc))
        }
    

    //如果类已经初始化过了就不会再调用initialize方法了

    
    

    [MJStudent alloc];等同于以下代码

    objc_msgSend([MJPerson class] @selector:(initialized))
    objc_msgSend([MJStudent class] @selector:(initialized))
    
    
    总结:
    +initialize和+load最大区别:
    +initialize是通过objc_msgSend进行调用的,所以有以下特点:
    1).如果子类没有实现+initialize,则会调用父类的+initialize;
    2).如果分类实现+initialize,则会覆盖父类的+initialize;(调用顺序为先编译后调用)
    2)initialize
    先初始化父类
    再初始化子类
    (可能最终调用的是父类的initialize方法)(可能会调用父类initialize多次,但不代表父类initialize多次,(父类initialize只有一次))
    
    1、调用方式的区别
    1)load是根据函数地址直接调用
    2)initialize是通过objc_msgSend调用
    2、调用时刻
    1)load是runtine加载类、分类的时候调用(只会调用一次)
    2)initialize是类第一次接收到消息的时候调用,每一个类只会initialize依次(父类的initialize方法可能会被调用多次)
    3、调用顺序的区别:
    +load:
    1).先调用类的+load;
    a.先编译的类,优先调用+load
    b.调用子类的+load之前,会调用父类的+load
    2).再调用分类的+load
    a.先编译的分类优先调用+load
    
    +initialize:
    1)先初始化父类,再初始化子类(可能最终调用的是父类的)

    相关文章

      网友评论

          本文标题:OC基础-category(3)

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