Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
16
Help us understand the problem. What is going on with this article?
@hongmhoon

Objective-Cのクラス初期化

More than 5 years have passed since last update.

Objective-Cのクラス初期化

  1. + (void)initializeを利用
  2. + (void)loadを利用
  3. __attribute__((constructor))を利用

*こちらの説明は動的ロードなどによる挙動は考慮してないです

1.+ (void)initializeを利用

呼ばれるタイミング

  • クラスが最初に利用される直前

注意点

  • サブクラスで+ (void)initializeを実装しないとスーパークラスの+ (void)initializeが呼ばれるので複数呼ばれる前提で実装する
@interface Parent : NSObject
@end
@implementation Parent
// このinitializeはParentクラスとChildクラスが最初に使われる時に
// 呼ばれるので2回呼ばれることになる。
// なのでクラスを確認するかdispatch_onceなどを利用して初期化する
+ (void)initialize
{
    if (self == [Parent self]) {
        NSLog(@"initialize %@", [self class]);
    }

//    dispatch_onceを利用
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        NSLog(@"initialize %@", [self class]);
//    });
}
@end

@interface Child : Parent
@end
@implementation Child
@end
  • + (void)initializeは各クラスで一度しか呼ばれないのでクラス本体でのみ実装してカテゴリでは実装しない
@implementation Parent
+ (void)initialize
{
    NSLog(@"initialize %@", [self class]);
}
@end

@implementation Parent (category)
// NG !!
+ (void)initialize
{
    NSLog(@"initialize %@", [self class]);
}
@end
  • クラスがプログラム内で利用されなければ呼ばれない

2. + (void)loadを利用

呼ばれるタイミング

  • クラスがメモリにロードされた直後、main関数が呼ばれる前

注意点

  • 他のクラスはまだロードされてない可能性があるので他のクラスは利用しない
@implementation Parent
+ (void)load
{
    // NG !!
    OtherClass *otherClass = [OtherClass new];
}
@end
  • クラス本体とカテゴリで複数実装すると全て呼ばれる
@implementation Parent
+ (void)load
{
    NSLog(@"load");
}
@end

@implementation Parent (category)
+ (void)load
{
    NSLog(@"load by category");
}
@end

@implementation Parent (category2)
+ (void)load
{
    NSLog(@"load by category2");
}
@end

3. __attribute__((constructor))を利用

呼ばれるタイミング

  • main関数が呼ばれる直前、全クラスがロード済み
@interface Parent : NSObject
@end

__attribute__((constructor))
static void initialize_class()
{
    NSLog(@"initialize_class");
}

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

+ (void)load
{
    NSLog(@"load");
}
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {

        Parent *p = [Parent new];
        NSLog(@"%@", p);
    }
}

// ログは以下のように表示される
// load
// initialize_class
// initialize Parent
// <Parent: 0xXXXXXXXXXXX>

注意点

  • これは正確に言うとObjective-Cの機能ではなくGCC提供の関数属性機能です。

GCC - Declaring Attributes of Functions

  • 複数の__attribute__((constructor))は優先度を指定して呼ばれる順番を指定可能
__attribute__((constructor(2)))
static void initialize_class2()
{
    NSLog(@"initialize_class 2");
}


__attribute__((constructor(3)))
static void initialize_class3()
{
    NSLog(@"initialize_class 3");
}


__attribute__((constructor(1)))
static void initialize_class1()
{
    NSLog(@"initialize_class 1");
}


// ログは以下のように表示される
// initialize_class 1
// initialize_class 2
// initialize_class 3
16
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
gunosy
情報キュレーションサービス「グノシー」や「ニュースパス」の開発・運営を通じて、情報を世界の人に最適に届けていきます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
16
Help us understand the problem. What is going on with this article?