ページ

2010年1月14日木曜日

+initialize は2度呼ばれる(場合あり)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

+initialize はクラスのイニシャライザ(初期化メソッド)。クラスがロードされた時に呼び出される。これが2度呼ばれることがある(状況によってはさらに複数回呼び出される)。

Mac Dev Center にそんな情報があった。

Mac Dev Center: Coding Guidelines for Cocoa: Tips and Techniques for Framework Developers

試してみよう。

ParentClass とそれを継承した ChildClass を作る。

ParentClass.h

@interface ParentClass : NSObject {

}

@end


ParentClass.m

#import "ParentClass.h"

@implementation ParentClass

+ (void)initialize
{
NSLog(@"initialize: %@", self);
}

@end


ChildClass.h

#import "ParentClass.h"

@interface ChildClass : ParentClass {

}

@end


ChildClass.m

#import "ChildClass.h"

@implementation ChildClass

@end




+initialize は ParentClass のみ実装し、ChildClass では実装しない。

これを実行時に、例えば AppDelegate などでインスタンス化する。


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

// [ChildClass self];
[[ChildClass alloc] init];
}


結果はこう。

Test[1116:80f] initialize: ParentClass
Test[1116:80f] initialize: ChildClass


ParentClass の +initialize が2回呼び出されいている。これはランタイムが使用するクラスへ +initialize を投げるのだが、派生クラスに実装がない場合は親クラスのメソッドが呼び出されるため(そういう意味ではクラスメソッドも、インスタンスメソッド同様にメッセージのルーティングが行われている)。


試しに ChildClass.m に +initialize を実装してみる。

#import "ChildClass.h"

@implementation ChildClass

+ (void)initialize
{
NSLog(@"initialize in ChildClass: %@", self);
}

@end


結果はこう。

Test[1199:80f] initialize: ParentClass
Test[1199:80f] initialize in ChildClass: ChildClass



先のりファンレスでは初期化処理が複数回呼び出されるのを避ける為に self をチェックするのが良いと書かれていた。

こんな感じ。


#import "ParentClass.h"

@implementation ParentClass

+ (void)initialize
{
if (self == [ParentClass class]) {
NSLog(@"initialize: %@", self);
}
}

@end


ChildClass の initialize を消して再び実行すると:


Test[1250:80f] initialize: ParentClass




派生クラスが想定される場合、親となるクラスでの +initialize を実装する場合は気を付ける必要がある。