読者です 読者をやめる 読者になる 読者になる

sandbox

Scala, Android, Architecture, Management, Service Design あたりを主戦場としております

Objective-C 2.0 プログラミング言語を読む #3 カテゴリ

カテゴリのところ。コード書く時に体に染みこませればいいので理解だけさらっと。

カテゴリとは

既存のビルトインクラスなどにメソッドを追加出来る。
また、自身のクラスにおいても実装を複数のファイルに分ける、つまりカテゴリ化することも出来る。

メソッドのクラスへの追加

インタフェース名の後にカテゴリ名を指定する。
中括弧がなく、インスタンス変数は定義できないことに注意。

#import "SampleClass.h"

@interface SampleClass(CategoryName)
//method declarations
@end

このカテゴリを定義したインターフェースファイルは命名規則により、
ClassName+CategoryName.h とする。

なので、これをインポートする実装ファイルは以下の様になる。

#import "SampleClass+CategoryName.h"

@implementation SampleClass(CategoryName)
//method implementations
@end

カテゴリの使いかた

  • クラスが継承している、また宣言されているメソッドをオーバーライドすることが出来る。
  • 同じクラスの別カテゴリに宣言されているメソッドは確実にオーバーライドすることは出来ない。
  • @interface セクションで宣言されているメソッドをオーバーライドするのは避けるべき。

ルートクラスのカテゴリ

カテゴリはルートクラスにもメソッドを追加出来る。
その為、NSObject を継承するすべてのクラスでそのメソッドが利用可能になる。
役立つこともあるかもしれないが、かなり危険。

#これは JavaScript のビルトインオブジェクトを拡張する際の問題と一緒かな。

クラス拡張

上記で説明してきた様なカテゴリの定義では、追加したメソッドに対する実装を必須としたくても
コンパイラがチェックしてくれない為、実装がなくてもコンパイル出来てしまう。

これを実装を必須としてメソッドを追加する場合にクラス拡張を使用する。

普通にカテゴリを定義した場合

@interface MyObject:NSObject 
{ 
  NSNumber*number; 
} 

- (NSNumber *)number; 
@end 

@interface MyObject (Setter) 
- (void)setNumber:(NSNumber *)newNumber; 
@end 

@implementation MyObject 
- (NSNumber *)number 
{ 
  return number; 
} 

//setNumber メソッドがなくてもコンパイル出来てしまう
@end 

クラス拡張を使用した場合

@interface MyObject :NSObject 
{ 
NSNumber *number; 
} 
- (NSNumber *)number; 
@end 

@interface MyObject () //括弧内を空にする。匿名カテゴリの様なイメージ。
- (void)setNumber:(NSNumber *)newNumber; 
@end 

@implementation MyObject 
- (NSNumber *)number 
{ 
  return number; 
} 

- (void)setNumber(NSNumber *)newNumber //ちゃんと実装しないとコンパイラに怒られる
{ 
  number = newNumber; 
} 
@end 

上記の様にメソッドを追加した場合は、コンパイラが setNumber のメソッドがないかをちゃんとチェックしてくれる。

読破するつもりだったけど

会議が入ったので読み終わるのは全然無理になった。。
さくっと理解して早くアプリ作りたいなぁ。