iOS【load与initialize】

2020-05-26  本文已影响0人  NJ_墨

摘录:枫叶无处漂泊

load类方法

load类方法特点:
load类方法调用的特点:

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

image

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

initialize

initialize类方法的特点:
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方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。

上一篇下一篇

猜你喜欢

热点阅读