スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Objective-CのProtocolについて

Objective-Cのプロトコルはどう実装されているのか。

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/Protocol.h>

@protocol SomeProtocol
- someMethod;
@end

int main() {
  Protocol *p = @protocol(SomeProtocol);
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}

@protocol(protocol_name)で、プロトコルの実体(Protocol *)を取得することができる。このコードをコンパイル、実行すると以下のようになる。

$ gcc test1.m -lobjc
$ ./a.out
SomeProtocol: 0x300c SomeProtocol

次に、@protocol(protocol_name)の代わりに、ランタイム関数であるobjc_getProtocol()を使ってみる。

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/Protocol.h>

@protocol SomeProtocol
- someMethod;
@end

int main() {
  Protocol *p = objc_getProtocol("SomeProtocol");
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}

同じようにコンパイル、実行する。

$ gcc test2.m -lobjc
$ ./a.out
SomeProtocol: 0x0 nil

今度はnilが返ってきたようだ。このプロトコル(SomeProtocol)はどこでも使用されておらず、このプロトコルの実体が作られなかったようだ。

今度は、SomeProtocolに適合したクラスを宣言してみる。

#include <objc/Protocol.h>
#include <objc/runtime.h>
#include <stdio.h>

@protocol SomeProtocol
- someMethod;
@end

@interface SomeClass <SomeProtocol>
- someMethod;
@end

int main() {
  Protocol *p = objc_getProtocol("SomeProtocol");
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}
$ gcc test3.m -lobjc
$ ./a.out
SomeProtocol: 0x0 nil

今度もnilが返ってきた。宣言するだけでは不足なようだ。次はクラスの実装も書く。

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/Protocol.h>

@protocol SomeProtocol
- someMethod;
@end

@interface SomeClass <SomeProtocol>
- someMethod;
@end

@implementation SomeClass
- someMethod { return nil; }
@end

int main() {
  Protocol *p = objc_getProtocol("SomeProtocol");
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}
$ gcc test4.m -lobjc
$ ./a.out
SomeProtocol: 0x30a4 SomeProtocol

取得できた。Class型のオブジェクトは、そのクラスが適合するプロトコルのリストを持つ(class_copyProtocolListで実行時に取得できる)ので、SomeProtocolの実体が作られたのだろう。

まとめ。Protocolの実体が作られる条件:

  • そのプロトコルに適合するクラス(カテゴリも?)の@implementationが書かれた
  • @protocol()で参照された

従って、どこからも参照されていないプロトコルを実行時にobjc_getProtocolで取得することはできない。

ちなみに、Protocolの実体はファイルごとに作られる。同じSomeProtocolであっても、あっちのファイル由来のものとこっちのファイル由来のものではアドレスが違う。protocol_isEqualで比較しよう。

スポンサーサイト

テーマ : プログラミング | ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

minoki

Author:minoki
好きなプログラミング言語:
Haskell,Lua
GitHubアカウント
Twitter

最新記事
月別アーカイブ
カテゴリ
検索フォーム
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。