閉じる


Objective-Cのソースコードを見てみよう

 

 


// インターフェイスファイル  MyClass1.h

 

#import <Foundation/Foundation.h>

 

// クラス型宣言 

@interface MyClass1 : NSObject // 親クラスがない場合は、NSObject 継承する。

{

            // データメンバ宣言

        int data_membar1;

        int data_member2;

}

 

    - (int)MyMethod1; // インスタンスメソッド宣言

    + (int)MyMethod2; // クラスメソッド宣言

 

@end

 


 

// 実装ファイル  MyClass1.m

 

#import <MyClass1.h>

 

// クラス型実装

@implementation MyClass1

 

    // -------------------

    // イニシャライザ実装 

       //

    // ( このメソッドは、allocメソッドによって、

       //       インスタンス確保された直後に呼び出される。)

    //

    - (id)init

    {

 

        self = [super init]; // 親クラスイニシャライザを呼び出す。

                            // ( 戻り値は、インスタンス自身)

 

 

        if ( self ) // 親クラス初期化処理失敗したら、nil が返される。

        {

            // メンバ初期化処理を、ここに書く。

        }

    

        return self; // そのまま返す。( これを子クラスが受け取る。)

    }

 

    // -------------------

    // デアロケータ実装 

       //

       // ( このメソッドは、releaseメソッドによって、

       //     インスタンス解放される直前に呼び出される。 )

 

    - (void)dealloc

    {

        // メンバ解放処理を、ここに書く。

 

        [super dealloc]; // 親クラス解放処理を呼び出す。

    }

 

    // -------------------

 

    - (int)MyMethod1 // インスタンスメソッド実装

    {

        

    }

 

    // -------------------

 

    + (int)MyMethod2 // クラスメソッド実装

    {

        

    }

 

    // -------------------

 

 

@end 

 


 

 // 実装ファイル  main.m

 

#import <Foundation/Foundation.h>

#import <MyClass1.h>

 

 

int main()

{

 

  @autorereasepool

  {

 

     // インスタンス生成し、イニシャライザ呼ぶ

     id obj1 = [[MyClass1 alloc]init]

     

     [obj1 MyMethod1];     // インスタンスメソッド呼ぶ

         [MyClass1 MyMethod1]; // クラスメソッド呼ぶ

 

  }

 

  return 0;

}

 

 

 

 


メソッドの宣言

 


 【メソッド宣言の書式】

 

- (戻り値)メソッド名;

 

(戻り値)メソッド名:(引数1のデータ型)引数1の名前;

 

(戻り値)メソッド名:(引数1のデータ型)引数1の名前

          引数2のラベル:(引数2のデータ型)引数2の名前;

 


 

 

・1文字目が、「-」のものは、「インスタンスメソッド」。

・1文字目が、「+」のものは、「クラスメソッド」。

 

 

引数1にはラベルがありませんが、

 これは、メソッド名最後に付ける慣習があるからです。↓

 


 

    - (int)getValueByIndex:(int) index_

                               Option:(int) option_;


 

 

ラベルは、メソッド呼び出す際にも書き添える必要があり、

 プログラマは、これを読むことによって、

 それぞれの引数の意味確認することができるのです。

 

 


メソッドの呼び出し

 


 【 メソッドの呼び出しの書式 】

 

 

   [レシーバー メソッド名];

 

   [レシーバー メソッド名:引数1];

 

   [レシーバー メソッド名:引数1

               引数2のラベル:引数2];

 


 

・「レシーバー」というのは、インスタンスメソッド

  持っているクラスインスタンスのことです。

 

クラスメソッドの場合は、クラス名を指定します。

 

 

・また、レシーバーには、メソッド呼び出しを使うこともできます。↓

 (この場合は、戻り値レシーバーになる。)


[[レシーバー メソッド名] メソッド名];


 

 

インスタンス自身へのポインタは、「self」です。↓


[self MyMethod1];


 

 

親クラスへのポインタは、「super」です。↓


[super MyMethod1];


 

・このように、superを書いた場合は、

 親クラスメソッドを、子クラス側オーバライド (上書き) していても、

 親クラスメソッドが呼び出されます。

 

 


インスタンスの確保と解放 ( alloc release )

 

 

 


 

// インスタンス確保解放。↓

 

MyClass1* p_obj1 = [[MyClass1 alloc] init]; // 確保

 

[release p_obj1]; // 解放

 

 


 

 ・1行目alloc メソッドは、

 「MyClass1クラスインスタンス生成してから、

 「MyClass1クラスinit メソッド (イニシャライザ) を呼んでいます。

 

・「イニシャライザ」は、インスタンス内メンバの初期化を行うメソッドで、

 C++でいうところのコンストラクタの役割を果たします。

 

 

2行目 release メソッドは、 

 「MyClass1クラスの dealloc メソッド (デアロケータ) を呼んでいます。

 

・「デアロケータ」は、インスタンス内メンバの解放を行うメソッドで、

 C++でいうところのデストラクタの役割を果たします。

 

 

 

【 インスタンス変数の正体 】

 

・「Objective-Cでは、クラスインスタンスは、

 すべて「スマートポインタ」になっています。

 

・「スマートポインタ」というのは、

 中にインスタンスへのポインタを入れておけば、

 使う人がいなくなった時点で、

 自動的に解放してくれるというアレです。

 

 

Objective-Cインスタンス変数は、

 インスタンス化された時点では、

 内部の参照カウンタが、になっています。

 

・そして、このインスタンス変数を利用している各インスタンス

 ぞれぞれリリースして行き、カウントが になると、

 内部で管理している実体が、自動的に解放されます。

 

 

Objective-C参照カウントは、「レテインカウント」といい、

 retainCountメソッド呼び出すことで、現在値取得することができます。↓


 NSLog( @"p_obj1のレテインカウントは、%d です。", [p_obj1 retainCount] );


 

 

 

レテインカウントは、retainメソッド呼び出す度に

 1ずつ カウントアップされていきます。↓


 [p_obj retain]; // これでカウント+1 された。


 

 ・つまり、deallocメソッド呼ばれるタイミングは、

 retainメソッド呼び出した回数 1回 だけ、

 releaseメソッド呼ばれた時です。

 

・ちなみに、「+1回」というのは、インスタンスの生成時に、

 allocメソッドによってカウントアップされたものです。

 

 

 ・retainメソッド呼び出すタイミングとしては、

 別のクラスにも、p_obj 持たせるために、

 そのイニシャライザなどへ、 p_obj 渡す時です。

 

・そして、releaseメソッド呼ぶタイミングは、

 そのクラスメンバ解放される時で、

 これは、デアロケータの中などです。

 

・このライフサイクルを、C++風に書くと、

 おおよそ、以下のようになります。↓

 


 // -------------------------

// 他のクラスに、メンバとして持たせるクラス宣言。↓

 

class Class1{ /* 中略 */ };

 

// -------------------------

// Class1インスタンス生成するクラス宣言

 

class Class2

{

   Class1* p_obj1;

 

   Class2()

   {

       p_obj1 = new Class1();

       // 参照カウント1 になる。この1は、作成者自身持ち分です。 )

    }

 

 ~Class2()

  {

       // delete p_obj1; とはせず、参照カウント減らす。( release )

  }

};

 

// -------------------------

// さらにそれを借り受け共有するクラス宣言。↓

 

 class Class3

{

   Class1* p_obj1; // 他のクラス生成したインスタンス

 

   Class3( Class1* p_obj_ )

   {

       p_obj1 = p_obj_

      // この時に、参照カウント増やす。( retain )

   }

 

  ~Class3()

  {

       // ここで参照カウント減らす。( release )

  }

};


 

 

 


自動解放プール ( autorelease )

 


 #import <Foundation/Foundation.h>

 

int main()

{

    // 自動解放プール生成する。

    NSAutoreleasePool* p_pool1 = [[NSAutoreleasePool alloc] init]

 

    MyClass1* p_obj1 = [[MyClass1 alloc] init];  // インスタンス生成する。 

 

    [p_obj1  autorelease]; // 自動解放プール登録しておく。

    // ( ※ 最後に生成されたプール登録される。)

 

    [p_pool1 release];  // 自動解放プール解放する。 ( p_obj1 解放される )

       

       return 0;

} 


 

 

インスタンスp_obj1」を、他のクラス共有する場合は、

 受け渡しの際に、retain メソッド呼び出して、

 レテインカウントカウントアップさせないといけません。

 

 

 

Foundationフレームワークメソッドでも、

  autorelease メソッドが呼ばれたインスタンスが返されるようになっています。

 

  ( ※ copy メソッドや、mutableCopy メソッド複製されたインスタンスは、

      autorelease メソッドが呼ばれていません。)

 

 

プール生成するのは面倒なので、ふつうは、次のように書きます。↓

 


 

#import <Foundation/Foundation.h>

 

int main()

{

 

   @autoreleasepool

   {

        // ここにコードを書く。     

   }

 

   return 0;

}


 

 



読者登録

hasehamさんの更新情報・新作情報をメールで受取りますか?(読者登録について