プロトコルって何?

今日はプロトコルって何?というわけで、「詳解 Objective-C 2.0」の「11-01 プロトコルの概念」「11-02 Objective-C におけるプロトコルの宣言」あたりを読んでみると、

  • プロトコル == Java でいうインタフェース == C++ でいう純粋仮想クラス
  • 「採用」はプロトコルを指定してクラスのインタフェースを宣言すること
  • 「適合」はプロトコルに含まれるメソッドを実装すること
って感じ。以上、なんですが、ちょっと試してみます。

以下だと MyObject1 に hello メソッドは用意されていない旨の警告を出しながらコンパイルは成功します。

#import <Foundation/Foundation.h>
 
@interface MyObject1 : NSObject
@end
 
@implementation MyObject1
@end
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    MyObject1* myObject1 = [[[MyObject1 alloc] init] autorelease];
    [myObject1 hello];
 
    [pool drain];
    return 0;
}

そこを、以下のように Greetings プロトコルを宣言して採用しておくと、こっちは MyObject1 が Greetings プロトコルを実装していない旨の警告を出しながらコンパイルは成功します。どっちにしろ Objective-C ではコンパイルは通ると。

#import <Foundation/Foundation.h>
 
@protocol Greetings
- (void)hello;
- (void)goodby;
@end
 
@interface MyObject1 : NSObject <Greetings>
@end
 
@implementation MyObject1
@end
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    MyObject1* myObject1 = [[[MyObject1 alloc] init] autorelease];
    [myObject1 hello];
 
    [pool drain];
    return 0;
}

以下のように hello と goodby を実装してあげると、無事警告はなくなります。

#import <Foundation/Foundation.h>
 
@protocol Greetings
- (void)hello;
- (void)goodby;
@end
 
@interface MyObject1 : NSObject <Greetings>
@end
 
@implementation MyObject1
- (void)hello {
    NSLog(@"hello");
}
 
- (void)goodby {
    NSLog(@"goodby");
}
@end
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    MyObject1* myObject1 = [[[MyObject1 alloc] init] autorelease];
    [myObject1 hello];
 
    [pool drain];
    return 0;
}

にゃるほど。

最後、NSObject の conformsToProtocol: を使うとオブジェクトがプロトコルに適合しているかどうか調べられるというわけでやってみます。

#import <Foundation/Foundation.h>
 
@protocol Greetings
- (void)hello;
- (void)goodby;
@end
 
@interface MyObject1 : NSObject <Greetings>
@end
 
@implementation MyObject1
- (void)hello {
    NSLog(@"hello");
}
 
- (void)goodby {
    NSLog(@"goodby");
}
@end
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    MyObject1* myObject1 = [[[MyObject1 alloc] init] autorelease];
    if ([myObject1 conformsToProtocol:@protocol(Greetings)]) {
        NSLog(@"myObject1 conforms to Greetings protocol");
    }
 
    [pool drain];
    return 0;
}

無事 “myObject1 conforms to Greetings protocol” が表示されます。じゃあ MyObject1 の hello メソッドの実装をコメントアウトして同じことをやってみたらどうなるのと思って試してみると、同じように “myObject1 conforms to Greetings protocol” と表示されとる。。じゃあ「採用」と「適合」の違いは?

「詳解 Objective-C 2.0」の「11-02 Objective-C におけるプロトコルの宣言」の「必須機能とオプションの指定」には、@required と @optional とでプロトコルを採用したクラスで実装必須なメソッドとそうでないメソッドを指定できるとのことなので、上の動きを見てみると、conformsToProtocol: よりも adoptsToProtocol: が名前として合っていて、プロトコルで @required と @optional を指定しない場合は @optional が指定されたのと同じ、が正しいような感じがしますが。。

というわけで、まだよく理解できていないんだなこれは。アガガ。

[2009/03/02 追記]
プロトコルが必要とされた背景とは? – なぜあえて静的な型を?」を読んでみると「オブジェクトがこのプロトコルを採用することを、プロトコルに適合している、という。」とのことなので、採用 == 適合、という理解で良いか。

[2009/03/04 追記]
@required と @optional については、@optional を指定するとメソッドの実装がなくてもコンパイラに怒られない(警告が出ない)だけですね。


About this entry