[Objective-c]インスタンス変数の書き方
《今回》第1回 ヘッダーファイルに書かない
第2回 カテゴリーを使う
第3回 クラスを継承する
[iPhoneアプリ開発]自作Frameworkをつくるシリーズ(リンク)で、再利用可能なモジュールをFrameworkとして切り出しました。
この作業では、ヘッダーファイルについて“公開用であること”を強く意識することになります。
不用意なバグを防ぐために、隠蔽できるものはきちんと隠蔽しておくべきでしょう。
これは、アクセスして良いものは、きちんとプロパティ宣言しておく(アクセッサを準備する)ということとセットです。
さて、今回からしばらくは“インスタンス変数を隠蔽できる場合、出来ない場合”というテーマで記事を書きます。
今回は、“インスタンス変数を隠蔽できる場合”です。
まずは、簡単なクラスを書きましょう。
1.BaseClass.h(インスタンス変数を書いたヘッダーファイル)
@interface BaseClass : NSObject { double ExponentNumber; } @property (nonatomic) double BaseNumber; -(void)setExponent:(double)exponentNumber; -(double)calculate; @end
説明のために、double型の変数を2通りの方法で宣言してみます。
- 「ExponentNumber」は、インスタンス変数として定義しています。
- アクセッサとなるメソッドを「-(void)setExponent:(double)exponentNumber;」として定義しています。
- 「BaseNumber」は、プロパティとして定義しています。
- 後述しますが、「@synthesizeディレクティブ」を用いることで、インスタンス変数の宣言は省略できます。
2.BaseClass.m
#import "BaseClass.h" @implementation BaseClass @synthesize BaseNumber; -(void)setExponent:(double)exponentNumber { ExponentNumber = exponentNumber; } -(double)calculate { return pow(BaseNumber, ExponentNumber); } @end
ヘッダファイルをimportして、「実装」を書くファイルです。
「@synthesize BaseNumber;」で、プロパティとインスタンス変数を紐づけています。
このように書いた場合、“同名のインスタンス変数”を暗黙に宣言したことになります。
3.(脇道の話)BaseClass.h(気分的に「しっかり感」のある書き方)
@interface BaseClass : NSObject { double ExponentNumber; double _BaseNumber; // 明示的に宣言する } @property (nonatomic) double BaseNumber; -(void)setExponent:(double)exponentNumber; -(double)calculate; @end
4.(脇道の話)BaseClass.m(気分的に「しっかり感」のある書き方)
#import "BaseClass.h" @implementation BaseClass @synthesize BaseNumber = _BaseNumber; // プロパティとインスタンス変数を明確に紐付ける -(void)setExponent:(double)exponentNumber { ExponentNumber = exponentNumber; } -(double)calculate { return pow(BaseNumber, ExponentNumber); } @end
5.BaseClass.h(インスタンス変数を隠蔽したヘッダーファイル)
話を元に戻します。
「ヘッダーファイルにインスタンス変数の定義を書かない」ということを実現しますので、とりあえず消しちゃいます。
@interface BaseClass : NSObject @property (nonatomic) double BaseNumber; -(void)setExponent:(double)exponentNumber; -(double)calculate; @end
6.BaseClass.m(インスタンス変数の定義を書いた)
消したものは、どこかに書かなきゃならないのですが、下記のように「@implementation」の中に書きます。
#import "BaseClass.h" @implementation BaseClass { double ExponentNumber; } @synthesize BaseNumber; -(void)setExponent:(double)exponentNumber { ExponentNumber = exponentNumber; } -(double)calculate { return pow(BaseNumber, ExponentNumber); } @end
もう一度繰り返します。
違いは、「@interface」という“インターフェース宣言”の中には、インスタンス変数の定義を書かずに、
「@implementation」という“実装”の中に、インスタンス変数の定義を書くのです。
これで、“公開するヘッダーファイルには、インスタンス変数が書かれない”ということが実現しました。
実際に、Appleが提供しているドキュメント(Objective-Cプログラミング言語:P38)にも、
インスタンス変数は実装詳細であり、通常、クラス自身の外からアクセスされることはあり ません。さらに、実装ブロック内に宣言すること、あるいは宣言済みプロパティから自動生 成させることも可能です。したがって通常は、インスタンス変数宣言をパブリックインター フェイスで行うべきではないので、波括弧も省略してください。
のように記載されています。
7.実行する
#import "BaseClass.h" -(void)doCalc { BaseClass* baseClass = [[BaseClass alloc]init]; baseClass.BaseNumber = 3; [baseClass setExponent:2]; double dd= [baseClass calculate]; NSLog(@"calculate result = %f",dd); }
こんな感じで動きを確認できます。
今回はここまでで、「インスタンス変数をヘッダファイルに書かない=隠蔽成功!」ということを指摘して終わりにします。
しかし、それで大喜びして色々とコードを書き換えた結果、思わぬエラーの山に遭遇したので、次回からその点について説明します。
ロゴスウェア
最新記事 by ロゴスウェア (全て見る)
- Amazon Linux(EC2)と PHPSTORM で Xdebug を行う - 2018年9月26日
- やらないことの合意 - 2018年6月27日
- 卒園アルバムとプロジェクトマネジメント - 2018年3月30日
Comments are closed.