読者です 読者をやめる 読者になる 読者になる

ニペブ - iPhone / iOSアプリ開発

iPhone / iOS アプリ開発方法と技術情報、入門レベルの初心者向けの記事を書いています。

Objective-C でのクラス変数・クラスメソッド・クラスオブジェクトの初期化

クラス変数/クラスメソッド と インスタンス変数/インスタンスメソッド

  • クラス変数やクラスメソッドは、プログラム全体を通して1つであり、クラスをインスタンス化しなくても使用する事ができ、クラス自体に紐づいている変数やメソッドです。
  • インスタンス変数やインスタンスメソッドは、クラスをインスタンス化(オブジェクトを生成)することにより使用することができ、オブジェクトに紐づいている変数やメソッドです。

クラスメソッドの定義と使用例

まずは、Objective-Cでのクラスメソッドの定義方法と使用例について説明します。

ファイル名:ClassMethodTest.h

クラスメソッドの宣言です。インスタンスメソッドが"-"で記載していたと思いますが、くらすメソッドは"+"で記載します。

#import <Foundation/Foundation.h>

@interface ClassMethodTest : NSObject

// クラスメソッドの宣言
+ (void)printLog;
// インスタンスメソッドの宣言n
- (void)printLog;

@end

ファイル名:ClassMethodTest.m

クラスメソッドの実装です。こちらも"+"で記載します。注意点としては、クラスメソッドからはインスタンス変数、インスタンスメソッドが使えません。
インスタンス変数やインスタンスメソッドはインスタンスに紐づいたものなので、クラスに紐づいたクラスメソッドからはどれを使えば良いか分からないので使えないのは当たり前ですね。
なお、クラスメソッド名とインスタンスメソッド名は同じものが使えます。

#import "ClassMethodTest.h"

@implementation ClassMethodTest

// クラスメソッドの実装
+ (void)printLog
{
    NSLog(@"クラスメソッド:");
}

// インスタンスメソッドの実装
- (void)printLog
{
    NSLog(@"インスタンスメソッド:");
}

@end

ファイル名:main.m

クラスメソッドは「[クラス名 クラスメソッド名]」という形式で呼び出します。
インスタンスメソッドと違い、クラスメソッドはプログラムのどこからでも呼び出す事が可能です。

#import <UIKit/UIKit.h>
#import "ClassMethodTest.h"

int main(int argc, char * argv[])
{
    // クラスメソッドの呼び出し
    [ClassMethodTest printLog];
    // インスタンスメソッドの呼び出し。そのため、オブジェクトを生成している。
    [[[ClassMethodTest alloc] init] printLog];
}

実行結果

クラスメソッド:
インスタンスメソッド:

クラス変数の定義と使用例

次に、Objective-Cのクラス変数について説明します。
しかし、実はObjective-Cにはクラス変数を定義するObjective-Cの構文がありません。
その代わりに、Objective-Cでは、実装ファイル(.m)の中でstatic指定子とともに定義された定数をクラス変数の代用として利用します。

static指定子を使って変数を定義すると、その変数はそのファイル内でだけで有効になります。
C言語では関数外で定義するとグローバル変数になってしまいます。そのため、static指定子を使って変数を定義する事により、クラス変数として隠蔽化することができます。
次の例は、先ほどの実装ファイルでクラス変数を定義し、それを使うクラスメソッドにしました。
クラス変数はクラスメソッド、インスタンスメソッドのどちらからも使えます。
なお、注意点として、クラス変数はクラスを通して1つしかありません。そのため、クラス変数の値を変更すると、そのクラス変数を使っている他の箇所にも影響が出てきます。

#import "ClassMethodTest.h"

static NSString *msg = @"こんにちは";

@implementation ClassMethodTest

// クラスメソッドの実装
+ (void)printLog
{
    NSLog(@"%@", msg);
}

// インスタンスメソッドの実装
+ (void)printLog
{
    NSLog(@"%@", msg);
}

@end

実行結果

クラスメソッド:こんにちは
インスタンスメソッド:こんにちは

クラスオブジェクトの初期化

最後に、クラスオブジェクトの初期化について説明します。
実は、クラス自体もClassクラスのオブジェクトなのです。そのため、クラスオブジェクトと呼んでいます。

さて、クラスオブジェクトも、クラス変数の初期化など初期化がしたい場合があると思います.。
その方法として、initializeメソッドを使う方法があります。クラスオブジェクトが使われる前にinitializeメソッドが呼ばれます。
なお、注意点として、initializeメソッドからスーパークラスのinitializeメソッドは明示的に呼び出してはいけません。

ファイル名:ClassInitializeTest.h

まずはinitializeメソッドを宣言します。

#import <Foundation/Foundation.h>

@interface ClassInitializeTest : NSObject
// initializeメソッドの宣言
+ (void)initialize;
// クラスメソッドの宣言
+ (void)printLog;
@end

ファイル名:ClassInitializeTest.m

次に、initilizeメソッドに処理を記載します。

#import "ClassInitializeTest.h"

// クラス変数
static const NSString *msg;

@implementation ClassInitializeTest

// initializeメソッドの宣言
// スーパークラスのinitializeメソッドは呼んではいけない
+ (void)initialize
{
    NSLog(@"初期化処理");
    msg = @"初期化済み文字列";
}

// クラスメソッドの実装
+ (void)printLog
{
    NSLog(@"クラスメソッド:%@", msg);
}
@end

ファイル名:main.m

メイン関数では単純にクラスメソッドを呼び出します。

#import <UIKit/UIKit.h>
#import "ClassInitilizeTest.h"

int main(int argc, char * argv[])
{
    // クラスメソッドの呼び出し
    [ClassInitilizeTest printLog];
}

実行結果

クラスを使用する前にinitilizeメソッドが呼び出され、クラス変数に値が代入されたため、次のような出力になっています。

初期化処理
クラスメソッド:初期化済み文字列

なにか、わかりづらい箇所や質問がありましたら、コメントやメールを頂けると助かります。