Objective-C NSObject,イニシャライザ,指定イニシャライザ 【初級編 第12回】

この記事は2012年11月13日に書かれたものです。内容が古い可能性がありますのでご注意ください。


Objective-C NSObject,イニシャライザ,指定イニシャライザ 【初級編 第12回】

前回Cocoaのコードに近づけるためにGNUstepをインストールしてFoundationフレームワークを使用できるようにしました。
そこで今までのコードを整理する意味でFoundationで用意されたクラスなどを使って書き換えてみましょう。

Bmi.h

#import <Foundation/NSObject.h>

@interface Bmi:NSObject

//BMI値を計算
+(double)calcBmi:(double)weight height:(double)height;
//適正体重を計算
+(double)calcProperWeight:(double)height;

@end

Bmi.m

#import "Bmi.h"

@implementation Bmi
    +(double)calcBmi:(double)weight height:(double)height{
        return weight/(height * height);
    }
    +(double)calcProperWeight:(double)height{
        return height * height * 22;
    }
@end

Person.h

#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>

@interface Person:NSObject
{
        //属性を表す
        double height;
        double weight;
}

//アクセサ
-(double)height;
-(void)setHeight:(double)personHeight;
-(double)weight;
-(void)setWeight:(double)personWeight;
-(id)initWithWeight:(double)personWeigth height:(double)personHeight;
@end

Person.m

#import "Person.h"

@implementation Person

        -(id)init{
                self = [self initWithWeight:65 height:1.71];
                if(self != nil){
                }
                return self ;
        }

        -(id)initWithWeight:(double)personWeight height:(double)personHeight{
                self = [super init];
                if(self != nil){
                        weight = personWeight;
                        height = personHeight;
                }
                return self;
        }

        -(double)weight{
                return weight;
        }
        -(void)setWeight:(double)personWeight{
                weight = personWeight;
        }
        -(double)height{
                return height;
        }
        -(void)setHeight:(double)personHeight{
                height = personHeight;
        }
@end

main.m

#import <Foundation/Foundation.h>
#import "Bmi.h"
#import "Person.h"

int main(void){
        Person *mine = [[Person alloc] initWithWeight:65.0 height:1.72];
        printf("%2.1fn",[Bmi calcBmi:[mine weight] height:[mine height]]);
        printf("%2.1fn",[Bmi calcProperWeight:[mine height]]);
        [mine release];
        return 0;
}

今までインポートしていた「Object.h」から「Foundation.h」と「NSObject.h」に変更しました。

#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>

そして「Bmi.h」や「Person.h」ではObjectクラスを継承していましたが、NSObjectクラスを継承するように
変えました。CocoaではNSObjectクラスがルートクラスとなっているからです。
NSObjectクラスはヘッダーファイルを見てみるとObjectクラスと用意されたインスタンス変数やメソッドが違っています。
私の環境では「/usr/GNUstep/System/Library/Headers/Foundation/NSObject.h」に配置されていました。

そのためルートクラスをNSObjectに変えたことで「main.m」内で使用していたメッセージ呼び出しでは処理の
できないものが出てきます。
それが「free」です。クラスをインスタンス化する際にはメモリ上のその領域が確保されるので、必要がなくなった場合
それを解放する必要があります。
Objectクラス内ではfreeと定義されていましたが、NSObjectクラスの場合は「release」を使用する形となります。

Foundationに変えたこととは関係ありませんが、Personの初期化処理の部分も少し変更しています。
その7で初期化するために「init」メソッドやinitでは引数を指定できないため、継承して作成したクラスで新たに
定義したインスタンス変数などを初期化するための「initWith~」といった引数の指定できるメソッドを
作成して使用するといいました。
これらの初期化のメソッドはイニシャライザと呼ばれます。

これらイニシャライザでは初期化をするわけですが、1つだけしか用意できないわけではなく複数用意できます。
複数作って用意したイニシャライザの中で、クラス中で初期化する必要のあるインスタンス変数へ値を格納するための
引数をすべて指定しているイニシャライザを特に指定イニシャライザといいます。
今回の例で言うと「-(id)initWithWeight:(double)personWeigth height:(double)personHeight」がこれに当たります。
Personクラスで用意したインスタンス変数である「weight」と「height」を初期化するための引数が指定してあります。

体重だけを指定する簡易的なイニシャライザを作成することもできます。作るとすればこんな感じですね。
この場合、身長は固定値で初期化などになるため指定イニシャライザとはなりません。
-(id)initWithWeight:(double)personWeight

こうした複数のイニシャライザを作成した際に注意するべき点として、Appleのドキュメントによると親クラスをたどって指定イニシャライザをつなげなければならないことです。
NSObjectクラスの指定イニシャライザはinitです。Personクラスの指定イニシャライザはinitWithWeight:hegintです。
そこでPerson.mでのinitWithWeightメソッドの中ではスーパークラスの指定イニシャライザであるinitを最初に
呼び出しています。
Personクラスのinitの方はインスタンス変数を初期化できないので指定イニシャライザとはなりません。
そこでPersonクラスのinitメソッドでは直接スーパークラスの指定イニシャライザを呼び出すのではなく、自身のクラスにある
指定イニシャライザを呼び出すようにします。そのクラス自身の初期化処理は指定イニシャライザに集めるということでしょうか。
実際の処理を見てみると65と1.71という初期値をセットしてメッセージを自身(self)に送信していますね。

複数のイニシャライザを作成する場合はこのようなことを意識する必要があります。

今回のまとめとしては

  • インスタンスの解放処理で使用するメッセージがNSObjectの場合、「release」になる
  • 初期化処理をするメソッドをイニシャライザと呼ぶ
  • イニシャライザは複数定義でき、その中で引数を完全に指定した一番重要なものを指定イニシャライザという
  • 指定イニシャライザは親クラスの指定イニシャライザへとつないでいく必要がある
  • そのほかのイニシャライザは自身のクラスの指定イニシャライザを使用して初期化を行う

といったところでしょうか。

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

PAGE TOP