Objective-C NSObject,イニシャライザ,指定イニシャライザ 【初級編 第12回】
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」になる
- 初期化処理をするメソッドをイニシャライザと呼ぶ
- イニシャライザは複数定義でき、その中で引数を完全に指定した一番重要なものを指定イニシャライザという
- 指定イニシャライザは親クラスの指定イニシャライザへとつないでいく必要がある
- そのほかのイニシャライザは自身のクラスの指定イニシャライザを使用して初期化を行う
といったところでしょうか。
TechProjin 開発系基礎講座 連載リンク
基礎からPHPWEBアプリ解発を学ぶなら・・
PHP基礎 連載
AIなどで注目急上昇!これから学ぶならPython!!
独学で学ぶ-pythonプログラミング 連載
汎用性◎ 定番プログラミング言語JAVA
Java基礎講座 連載