今朝のObjective-Cの勉強

Tsukasa OISHI

朝早く起きて、Objective-Cの勉強をちょっとしました。

今日覚えたこと。

1.インスタンス変数とself
インスタンス変数は@interfaceディレクティブで指定してあげます。

@interface Test : Object
{
        int     prt_attr;
@public
        int     open;
@private
        int     num;
        char *  name;
}

@public,@protected,@privateディレクティブで公開範囲を指定します。何も指定していないときは@protectedが選択されます。
メソッド内でインスタンス自体にアクセスしたいときはselfを使います。

  self->num = 3;

注意が必要なのが、@publicなインスタンス変数を外部から利用するとき。id型の変数からは@publicなインスタンス変数を参照できません。

  id obj = [Test new];
  obj->open = 3; // これはNG

そのときは

  Test * obj = [Test new];
  obj->open = 3; // これはOK

というように静的な型としてコンパイラが確認できるようにしてあげます。

2.メソッドのラベル
メソッドにはラベルをつけることができます。同じメソッド名でもラベルが異なれば別のものとして扱われます。

  - (void)method:(int)num andName:(char*)name {
    printf("lavel on\n");
  }
  - (void)method:(int)num :(char*)name {
    printf("lavel off\n");
  }
......
  [obj method:1:"test"];
  [obj method:1 andName:"tsukasa"];

とすれば、

lavel off
label on

となります。引数の間にラベルを置くみたいです。最初は引数それぞれにラベルをつけられるのかと思っていました。引数が3つあれば

- (void)method:(int)num andName:(char*)name andAge:(int)age;

というふうに書けます。

3.指定イニシャライザ
インスタンスを生成するときに初期値も指定してあげたいときがよくあります。そんなときに使うのが指定イニシャライザ。Objective-Cでは、newクラスメソッドで[Class alloc init]とメッセージを投げているので、initメソッドをオーバーライドすればよさそうですが、こいつは引数を受け取れません。そこで、

  - (id)init {
          [super init];
          return [self initWith:1 :"oishi"];
  }

  - (id)initWith:(int)num :(char*)name{
          self->num = num;
          self->name = name;
          return self;
  }

というように、initメソッドから引数を受け取る指定イニシャライザを呼んであげます。慣例的に、指定イニシャライザはinitWithで始まるメソッド名にするようです。main()で実際にこれを利用するときは、

Test * obj = [[Test alloc] initWithNum:5 :"tsukasa"];

みたいな感じで呼びます。そのままですね。

4.ガベージコレクション
Objective-Cにはガベージコレクションなどありません。まさにC言語です。インスタンス生成で確保したメモリを開放するときはfreeインスタンスメソッドを呼んであげます。

  [obj free];

これ、忘れそうですね。Rubyとかに慣れている身としては。注意が必要です。

5.クラスオブジェクト
Objective-Cではクラス自体をオブジェクトとして利用することができます。クラスオブジェクトを引き出すときはclassメソッドを使います。型はClassとなります。

  Class c_obj = [Test class];
  id obj => [c_obj new];

6.セレクタ
Objective-Cではメッセージのやりとりにセレクタというものを使って実際のメソッドを特定しているようです。
セレクタを使えば実行中に呼び出したいメソッドを動的に選択することができるようになります。C言語の関数へのポインタみたいですね。セレクタを取得するには@selectorディレクティブを使います。返される型はSEL型です。

  SEL call_m = @selector(openMethod);
  [Test perform:call_m];

performメソッドはセレクタを受け取って、それが示すメソッドを実行します。

7.メソッドへのポインタ
メソッドへのポインタを取得することができます。取得したそれはC言語の関数へのポインタと同じように使うことができます。メソッドへのポインタを取得するには、instanceMethodForクラスメソッド、またはmethodForインスタンスメソッドを使います。これらはメソッドへのポインタをIMP型として返します。

  id obj = [Test new];
  SEL method_sel = @selector(method);
  IMP func = [obj methodFor:method_sel];
  func(obj, method);

メソッドへのポインタの第一引数にオブジェクト、第二引数にメソッドのセレクタ、それ以降に通常の引数を指定します。

8.プロトコル
JavaのインターフェースのようなものがObjective-Cにもあって、プロトコルと呼ばれています。

@protocol Tsukasa
- (void)oishi;
@end

@interface Test : Object <Tsukasa>
@end

というように、プロトコルを採用するクラスの宣言で 内に指定してあげます。プロトコルが採用されたクラスでは必ずそのメソッドを実装しなければなりません。