[Objective-c]インスタンス変数の書き方(第1回 ヘッダーファイルに書かない)

[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);
}


こんな感じで動きを確認できます。

今回はここまでで、「インスタンス変数をヘッダファイルに書かない=隠蔽成功!」ということを指摘して終わりにします。
しかし、それで大喜びして色々とコードを書き換えた結果、思わぬエラーの山に遭遇したので、次回からその点について説明します。

The following two tabs change content below.

ロゴスウェア

ロゴスウェア株式会社は、インターネットや情報技術を使って学習に革新的進化をもたらす製品を開発することを目標に、2001年7月に設立されたテクノロジー系ベンチャー企業です。

Comments are closed.