Objective-C以前こんな記事を書きました。次は、カテゴリについて勉強したいと思います。/var/log/shinなーんて書いてから、はや9ヶ月超。カテゴリについて調べる機会が来たので、まとめてみます。座学編クラスの基本まず初めにクラスの基本を整理しておきます。0;}コンパイル、実行します。publicMethod]後々のために、ここで述べておきますが、同名の@interfaceや@implementationは宣言することはできません。これ以上の詳細に関しては、前に痛い記事を書いていますので良かったら読んでみて下さい。/var/log/shinカテゴリカテゴリを使えばクラスを拡張できるよ、という話は少し調べれば分かることなのですが、じゃあ何でクラスを拡張できるような機能の名前が「カテゴリ」なんだよ、という疑問が浮かんだので調べてみました。このサイトによれば、カテゴリは元々クラスを分割して書くことが出来るようにするため考えられた言語機能のようです。クラスを書いていると、しばしば互いに関連しているメソッドが出てくるので、そういった機能のまとまりを「カテゴリ」化して、別々に*1実装できたら嬉しいじゃん、ということですね*2。カテゴリのサンプルコードを載せます。0;}以上をコンパイルして実行します。カテゴリ無いバージョン。./a.outHelloWorldprintAsHtmlメソッドが無いと怒られますが、問題なく実行できます。次に、カテゴリ有りバージョンです。./a.outHelloWorld<h1>Hello</h1><p>World</p>ちゃんとHTMLでの出力がされています。以下、ポイントを箇条書きで列挙します。ポイントは、document.h、document.mがそれだけで完結していることです。それら2つのファイルが関知していない、document-ex.hでDocumentクラス本体を拡張できていることが分かるかと思います。document.hでインスタンス変数宣言をしていますが、document.mの@synthesisで自動生成されるので書く必要ないじゃない、と思われるかもしれません。何で書いているのかというと、カテゴリからインスタンス変数を参照するに必要だからです。良い実装をするなら、document.hで変数宣言せず、カテゴリ側はプロパティ経由でアクセスするようにすれば良いのですが、今回はカテゴリでインスタンス変数にアクセスできるんだよということを示したかったので、あえてこのようにしました。カテゴリにはインスタンス変数を追加することが出来ません。既存のインスタンス変数には@privateなものについてもアクセスできます。main.mでrespondsToSelectorを使っています。これは、指定のセレクタのメソッドが実装されているかをチェックするNSObjectのメソッドです。カテゴリの実装を含めてコンパイルした場合はメソッドが実装されているので真が返る仕組みです。コンパイル時にwarningが出るのは、document.hにカテゴリで拡張されるメソッドが宣言されてないので、コンパイラがメソッドを見つけられないためです。プロジェクト内でカテゴリを使う場合は、カテゴリ側でちゃんとヘッダを用意して、適宜importすべきだと思います。カテゴリを利用すればクラスの実装を分割することが出来るということでした。別の見方をすれば、この機能を使えば、既存のクラスの実装に一切手を付けずに既存のクラス自体にメソッドを追加することができるということです。よって、NSObjectやUIViewなど既存のライブラリが提供しているクラスも、クラス本体を拡張できます。extension)ここまで、カテゴリ使えばクラスを拡張できるよ、という話をしてきました。次に見ていくのは「クラス拡張」という機能です。「クラス拡張」はカテゴリとは別物のObjectice-Cの一機能です*3。クラス拡張は、無名のカテゴリに似ています。違いは、インスタンス変数を宣言できることと、宣言したメソッドはクラス本体の(=カテゴリ無しの)@implementationで実装しなければならない点です。これだけみると何でこんな変な機能があるのかと思うかもしれませんが、つまるところ何がしたいかというと、ヘッダに公開したくないメソッドや変数を隠したいのです。C++でいうところのpimplイディオム的なものだと考えればよいでしょう。それ以外の用途はほとんど無いと考えて問題ないと思います。いうわけでサンプルコードです。0;}コンパイル、実行します。./a.out0123ただし、今回のケースの場合、クラス拡張を使わない次のような実装でもOKです。}@end公式ドキュメントによると、@property宣言を追加してたりしますが*4、実際の所、インスタンス変数やメソッドに関しては、最近のコンパイラの実装では全部@implementation側に書けるので(参考)、本当に@property関係くらいでしかこの機能を使う機会は無いのかもしれません*5。実際にカテゴリやクラス拡張を使っている実例を色々探してみたので記録しておきます。GitHub言わずと知れたMacのエディタですね。AppControllerクラスでファイルの分割のためにカテゴリが使われています。カテゴリの宣言はクラス本体の宣言と同じAppController.hに書かれています。大多数のインスタンス変数はカテゴリから参照するためか、ヘッダ側に書かれています。I/Oライブラリっぽいです。JSONKit.hでNSArrayやNSDictionaryなどがカテゴリでバリバリ拡張されています。GitHubAndroidのToast的なiOSのUIライブラリ。Toast+UIView.mでUIViewをカテゴリで拡張しています。カテゴリで宣言するメソッドはどこかで実装されていればOKです。その特性を利用して、privateなメソッドについて、宣言だけは”〜Private”のような名前のカテゴリで行い、実装は1つの@implementation内に書いてしまうというパターンがこのプロジェクトに限らずちょくちょく見受けられます。マイナビニュースこの連載記事は全体通してかなりマニアックで充実した内容なので、じっくり読みたいところです。BLOGXcode4.3,4.4辺りから使える、新しいモダンな書き方のまとめ*1:別ファイルで*2:先に述べたとおり、同名の@implementationは複数書けません。カテゴリがなかったら、クラスの実装は1つ@implementation内に=1つのファイル内に記述しないといけません。*3:このエントリーを真面目にまとめようと思ったきっかけがこのクラス拡張です。見た時は唖然としました。*4:プロパティの再宣言による属性の変更も可能*5:Xcodeのプリセットのスケルトンコードではインスタンス変数がクラス拡張部分に書かれていたりします。このあたりは好みの問題でしょうかね。NSURLConnectionのまとめiOSでネットワーク通信をするのは初めてだったのでメモ。»プロフィールid:s-shinプログラマブルな人間になりたい。(1)リンクヘルプはてなブログお知らせはてなブログをはじめよう!s-shinさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。