この記事にリンクして、詳細に書いてくれている記事があったので紹介。
Objective-Cの内部実装にも触れて分かりやすく書いてくれているので、より どういう違いがあるかが分かるかと思います。
AppleのiOS View Controllerプログラミングガイドを読んでいて気づいた。
なんで実装ファイルの方で@interface
を宣言しているんだろうと思っていたのだけど、これはどうやら クラス拡張 というものらしい。
似たような仕組みに、 カテゴリ がある。
カテゴリは@interface Hoge(anyCategory)
で宣言するやつ。
これを無名にしている(つまり@interface Hoge()
)のが、実装ファイルでよく書かれているやつだ。
なるほど、無名カテゴリだから()
なのか。
と腑に落ちたことをTwitterでつぶやいたら、「いや、厳密には違う」と指摘をもらった。
調べてみたら、どうやら クラス拡張 という機能で、カテゴリとは厳密には違う仕組みのよう。
参考にした記事から引用させてもらうと、
クラス拡張は、無名のカテゴリに似ています。が、別物です。一番の違いは、インスタンス変数を宣言できることと、宣言したメソッドはクラス本体の(=カテゴリ無しの)@implementationで実装しなければならない点です。
ということらしい。
確かに外部に公開しないメソッドとかを宣言していたなーと気づいた。
つまりまとめると、
- 実装ファイルに書かれている
@inteface
部は クラス拡張 の宣言 - 実装ファイルの
@implementation
は カテゴリなし の実装部分のため、クラス拡張の宣言をしっかりと実装しているために問題なし
ということか。
サンプルコード
// Hoge.h
#import <Foundation/Foundation.h>
// 公開メソッド
@interface Hoge : NSObject
- (void)foo;
- (void)bar;
@end
// Hoge.m
#import "Hoge.h"
// クラス拡張
// ヘッダーに公開されないメソッドとインスタンス変数
@interface Hoge () {
int _count;
}
- (void)method;
@end
@implementation Hoge
- (void)foo { }
- (void)bar { }
- (void)method { }
@end
##コメントもらったので追記
よく使われるテクニックとして、ヘッダにreadonlyのプロパティを宣言しておき、外部からは読み取り専用にしつつ、実装側のクラス拡張機能でreadwriteにして読み書きできるようにする、というものがあるみたいです。確かに便利そう!
参考にさせてもらった記事は以下です。