美文网首页
第51条:精简initialize与load的实现代码

第51条:精简initialize与load的实现代码

作者: MrSYLong | 来源:发表于2018-10-18 22:11 被阅读17次

有时候类,必须先执行某些初始化操作,然后才能正常使用。在Objective-C中,绝大多数类都继承自NSObject这个根类,而该类有两个方法可以用来实现这种初始化操作。

首先是load方法:

+ (void)load

加入运行期系统中的每个类及分类,都会调用此方法,而且仅调用一次。在iOS中,这类方法会在应用程序启动时执行(Mac OS X中可以使用动态加载,程序启动之后再加载)。在执行load方法时,是先执行超类的load方法,再执行子类的,先执行类的,再执行其所属分类的,如果某个类没有实现load方法,不管其各级超类是否实现此方法,系统都不会调用。如果代码还依赖了其他程序库,则会有限执行该程序库中的load方法。但在给定的某个程序库中,无法判断出各个类的载入顺序。

#import <Foundation/Foundation.h>
#import "EOCClassA.h" // 来自同一个库

@interface EOCClassB : NSObject
@end

@implementation EOCClassB

+ (void)load{
    NSLog(@"Loading EOCClassB");
    EOCClassA *object = [EOCClassA new];
    // ues object
}
@end

这段代码不安全,因为无法确定EOCClassA已在执行EOCClassB load方法时已经加载好了。

load方法不遵从普通方法的继承规则,如果某个类本身没实现load方法,那么不管其超类是否实现此方法,系统都不会调用。

load方法应该尽量精简,因为整个程序执行load方法时都会阻塞。不要在里面等待锁,也不要调用可能会加锁的方法。总之,能不做的事情就别做。

想要执行与类相关的初始化操作,还有个方法,就是覆写下列方法:

+ (void)initialize

对于每个类来说,该方法会在程序首次调用该类之前调用,而且只调用一次。

initialize与load方法主要有3个区别:

  1. initialize方法只有当程序用到了相关类才会调用,而load不同,程序必须阻塞并等所有类的load都执行完毕,才能继续。
  2. 运行期系统执行initialize方法时,处于正常状态,而不是阻塞状态。为保证线程安全,只会阻塞其他操作该类或类实例的线程。
  3. 如果某个类未实现initialize方法,而超类实现了它,那么就会运行超类的方法。

initialize方法也应当尽量精简,只需要在里面设置一些状态,使本类能够正常运作就可以了,不要执行那种耗时太久或需要加锁的任务,也尽量不要在其中调用其他方法,即使是本类的方法。

无法在编译期设定的全局常量,可以放在initialize方法里初始化。

// EOCClass.h
#import <Foundation/Foundation.h>

@interface EOCClass : NSObject
@end

// EOCClass.m
#import "EOCClass.h"

static const int kInterval = 10;
static NSMutableArray *kSomeObjects;

@implementation EOCClass

+ (void)initialize{
    // 判断类的类型,防止在子类中执行
    if(self == [EOCClass class]){
        kSomeObjects = [NSMutableArray new];
    }
}
@end

整数可以在编译期定义,然而可变数组不行,下面这样创建对象会报错。

static NSMutableArray *kSomeObjects = [NSMutableArray new];

相关文章

网友评论

      本文标题:第51条:精简initialize与load的实现代码

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