プロトコルの使い道
Objective-Cの"プロトコル"はJavaやC#のインタフェースとほぼ同じ概念だ。インタフェースにより型の抽象度を上げたり、多態を実現したりと、型を拡張することができる。
Objective-Cは通常のクラスの継承の他に型を拡張するのに強力な"カテゴリ"があり、この"カテゴリ"を利用した"非形式プロトコル"により緩い型制約※を実現できることもあり、正直プロトコルの意義はあまり無いのではないかと思っていたが勿論そんなことは無い。
Objective-Cのプロトコルはその名前の通り型の規定であり、ゆるゆるなその型に対して制約を適用する際に使えば良い(のだと思う)
例えば、同期/非同期で処理を実行するAndroidのAsyncTaskクラスのような処理を考えてみよう。インタフェースとしては特定のメソッドが実装をされていることを制約としたいので、以下のようなプロトコルを考えてみる。
BBAsyncTaskProtocol.h
@protocol BBAsyncTaskProtocol <NSObject> - (id)executeInBackgound:(id)params; - (void)postExecute:(id)executeResult; @end
タスクを実行する処理では、シグネチャで通常のオブジェクトであることの他にBBTaskProtocolに準拠しているオブジェクトのみ受け入れるように書くことが出来、余計な型検査処理を省くことができる。
- (void)runTask:(id<BBTaskProtocol>)targetTask { //引数targetTaskの型はどんなクラスでも構わないが、BBTaskProtocolに準拠している必要がある。、 }
また、仮に処理で検査が必要になったとしても非形式プロトコルのようにメソッド毎に検査する必要は無く、conformToProtocol:メソッド一発で適合を検査することがでぎる。
- (id)initWithTarget:(id)target { BOOL conform = [target conformsToProtocol:@protocol(BBTaskProtocol)]; NSAssert( conform, @"targetObject must be conforms BBTaskProcol"); self.targetObject = target; return self; }
とかくゆるゆるな型のobjective-Cだが、プロトコルを使うことで柔軟に制約を付加することができる。
※Objective-C 2.0以降、プロトコルは@required、@optionディレクティブによりそれぞれ"実装は必須"、"実装はオプション"と分けることができる訳で緩い型制約も実現できるようになっている。