[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.

谷中

システム開発チームと検証チームのマネージャー。 「疎結合 小さなクラス 分業制」 を裏スローガンとし、これが実現できてこそ、幸せな開発者人生を過ごせるという確信のもと、上流から設計まで口を挟んだり挟まなかったりしています。

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>