美文网首页
iOS【load与initialize】

iOS【load与initialize】

作者: NJ_墨 | 来源:发表于2020-05-26 11:03 被阅读0次

    摘录:枫叶无处漂泊

    load类方法

    load类方法特点:
    • 当类被导入到项目的时候就会执行load函数,
    • 在main函数开始执行之前的,这个类是否被用到无关
    • 每个类的load函数只会自动调用一次
    • load函数是系统自动加载的,不需要调用父类的load函数
    load类方法调用的特点:
    • 父类和子类都实现load函数时,父类的load方法执行顺序要优先于子类。
    • 子类未实现load方法时,不会调用父类load方法
    • 类中的load方法执行顺序要优先于类别(Category)
    • 有多个类别(Category)都实现了load方法,这几个load方法都会执行,但执行顺序不确定(其执行顺序与类别在Compile Sources中出现的顺序一致)

    查看一下Compile Sources的文件顺序,如下图:

    image

    执行顺序和Compile Sources顺序是一样的。

    • 有多个不同的类的时候,每个类load 执行顺序与其在Compile Sources出现的顺序一致

    initialize

    initialize类方法的特点:
    • 即使类文件被引用进项目,但是没有使用,initialize不会被调用

    • 假如这个类放到代码中,而这段代码并没有被执行,这个函数是不会被执行的。

    • 类或者其子类的第一个方法被调用前调用

    • 由于是系统自动调用,也不需要再调用 [super initialize] ,否则父类的initialize会被多次执行

    initialize类方法调用的特点:
    • 父类的initialize方法会比子类先执行

    • 子类未实现initialize方法时,会调用父类initialize方法,子类实现initialize方法时,会覆盖父类initialize方法.

    • 当有多个Category都实现了initialize方法,会覆盖类中的方法,只执行一个(会执行Compile Sources 列表中最后一个Category 的initialize方法)

    我们在Student.m(继承Person)中不实现initialize方法,

    //Person.m
    +(void)initialize {
    
         NSLog(@"%s",__FUNCTION__);
    }
    
    //Student.m
    Student中不实现initialize方法
    

    执行一下

    [Student new];
    

    直接结果:

    [Person initialize]
    [Person initialize]
    

    注意:为啥执行两遍,因为父类会比子类先执行,先执行父类的,子类没有实现的,会调用父类initialize方法,所以执行了两遍。

    Load使用情况

    load很常见的一个使用场景,交换两个方法的实现,称之为method swizzling

    
    
    +(void)load {
        
        static dispatch_once_t oneToken;
    
        dispatch_once(&oneToken, ^{
    
               Method imageNamed = class_getClassMethod(self,@selector(imageNamed:));
        Method mkeImageNamed =class_getClassMethod(self,@selector(swizze_imageNamed:));
        method_exchangeImplementations(imageNamed, mkeImageNamed);
       
       });
    }
    
    + (instancetype)swizze_imageNamed:(NSString*)name {
        
        //这个时候swizze_imageNamed已经和imageNamed交换imp,所以当你在调用swizze_imageNamed时候其实就是调用imageNamed
         UIImage * image;
        if( IS_IPHONE ){
            // iphone处理
            UIImage * image =  [self swizze_imageNamed:name];
            if (image != nil) {
                return image;
            } else {
                return nil;
            }
        } else {
            // ipad处理,_ipad是自己定义,~ipad是系统自己自定义。
            UIImage *image = [self swizze_imageNamed:[NSString stringWithFormat:@"%@_ipad",name]];
            if (image != nil) {
                return image;
            }else {
                image = [self swizze_imageNamed:name];
                return image;
            }
    }
    

    这个就是抵用系统imageNamed方法,在这基础上对ipad的图片进行适配,这样的每次调用imageNamed
    不用在对ipad和iphone进行适配。

    #import "UIFont+Extension.h"
    #import <objc/runtime.h>
    #import "NSObject+Swizzling.h"
    #import "Constants.h"
    
    ///苹果字体效果: http://www.iosfonts.com/
    static NSString * const kGlobalFontName = @"ProximaNova-Regular";
    static NSString * const kGlobalBoldFontName = @"ProximaNova-Semibold";
    
    
    @implementation UIFont (Extension)
    
    /**
     * 替换全局设置字体方法
     */
    +(void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Class class = [self class];
            //系统字体
            Method orignal_system = class_getClassMethod(class, @selector(systemFontOfSize:));
            Method zf_system = class_getClassMethod(class, @selector(zf_systemFontOfSize:));
            method_exchangeImplementations(orignal_system, zf_system);
            
            //系统粗体字体
            Method orignal_bold = class_getClassMethod(class, @selector(boldSystemFontOfSize:));
            Method zf_bold = class_getClassMethod(class, @selector(zf_boldSystemFontOfSize:));
            method_exchangeImplementations(orignal_bold, zf_bold);
        });
    }
    
    /// [UIFont systemFontOfSize:(CGFloat)]
    + (UIFont *)zf_systemFontOfSize:(CGFloat)fontSize {
        return [UIFont fontWithName:kGlobalFontName size:fontSize];;
    }
    
    /// [UIFont boldSystemFontOfSize:(CGFloat)];
    + (UIFont *)zf_boldSystemFontOfSize:(CGFloat)fontSize {
        return [UIFont fontWithName:kGlobalBoldFontName size:fontSize];;
    }
    
    @end
    

    initialize使用情况

    initialize方法主要用来对一些不方便在编译期初始化的对象进行赋值。

    比如NSMutableArray这种类型的实例化依赖于runtime的消息发送,所以显然无法在编译器初始化:

    // In Person.m
    // int类型可以在编译期赋值
    static int someNumber = 0; 
    static NSMutableArray *someArray;
    + (void)initialize {
        if (self == [Person class]) {
            // 不方便编译期复制的对象在这里赋值
            someArray = [[NSMutableArray alloc] init];
        }
    }
    

    总结

    1、load和initialize方法都会在实例化对象之前调用

    2、load执行在main函数以前,initialize执行main函数之后

    3、这两个方法会被自动调用,不能手动调用它们。

    4、load和initialize方法都不用显示的调用父类的方法而是自动调用

    5、子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类

    6、initialize方法对一个类而言只会调用一次(Person、或者是Person+Category)都是一个Perosn类。load方法则是每个都会调用,只要你写了load方法,添加到工程都会实现。

    7、load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。

    8、load和initialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。

    相关文章

      网友评论

          本文标题:iOS【load与initialize】

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