前回はProxyパターンを実現する、NSProxyクラスについて説明した。今回は、実際にこのクラスを使うことを説明しよう。
NSConnectionを使ったコネクションの設定
NSProxyは、スレッド間通信、またはプロセス間通信で使われる訳だが、NSProxy自体は遠距離にあるオブジェクトの「代理人」の役割を果たすにすぎない。実際には、通信を行ってくれるクラスも必要である。まずは、そこから説明しよう。
この通信を行ってくれるクラスは、NSConnectionである。このクラスが、異なるスレッド、または異なるプロセスの間をつないでくれる。さらに、ネットワーク越しの通信も可能である。
ここでは、同一ホストにあるプロセス間の通信を例に挙げて説明しよう。この場合は、まずNSConnectionに「名前」をつける。この名前を使うことで、どのプロセスからもアクセスできるのだ。
次に、メッセージ通信で呼ばれる側、つまりサーバとなる側の設定だ。ここでは、他のプロセスからのメッセージを受け取るオブジェクトを設定しておく。これを、ルートオブジェクトと呼ぶ。
これらの設定には、次のメソッドを使う。
List 1. NSConnection.h
- (BOOL)registerName:(NSString*)name;
- (void)setRootObject:(id)anObject;
そして呼び出す側、つまりクライアント側では、先ほど設定したルートオブジェクトのプロキシを使うことになる。これを取り出すには、rootProxyForConnectionWithRegisteredName:host:というメソッドを使う。
List 2. NSConnection.h
+ (NSDistantObject*)rootProxyForConnectionWithRegisteredName:(NSString*)name host:(NSString*)hostName
名前には、さきほど登録したNSConnectionの名前を使う。ホスト名は、ネットワーク上でのホストの名前だ。同一ホストにある場合は空文字を指定しておく。
これらを使えば、プロセス間通信ができるのだ。
実際の通信
では、実際に通信してみよう。プロセス間通信なので、2つのアプリケーションを作ることになる。
まず、呼び出される側、つまりサーバ側を説明しよう。ここでは、Serverというクラスを作ってみる。こちらで行うことは、NSConnectionへの名前の登録と、ルートオブジェクトの設定だ。次のようにしよう。
List 3. Server
- (void)register
{
NSConnection* connection;
connection = [NSConnection defaultConnection];
[connection registerName:@"Server"];
[connection setRootObject:self];
}
NSConnectionのインスタンスを取得して、名前を付ける。そしてルートオブジェクトとして、自分自身を設定しておいた。これで、送られてきたメッセージは、このServerクラスが受け取ることになる。
続いて、クライアント側だ。こちらでは、プロキシを取得する。
List 4. Client
- (void)invokeServer
{
id proxy;
proxy = [NSConnection
rootProxyForConnectionWithRegisteredName:@"Server" host:@""];
}
先ほど登録した名前を使って、NSConnectionからプロキシを取得している。
これだけで、すべての準備は完了だ。あとは、プロキシに対してメソッド呼び出しを行えば、それはサーバに送られる。
NSDistantObjectによる通信の効率化
NSConnectionから得られたプロキシについて、もう少し説明しよう。これは、NSDistantObjectというクラスになっている。このクラスは、NSProxyのサブクラスだ。このサブクラスでは、通信に便利なメソッドが追加されている。
スレッド間通信やプロセス間通信で一番問題となるのは、そのパフォーマンスだ。同一スレッド内でのメソッド呼び出しと比べると、当然のことだが、圧倒的に時間がかかる。これは、ある程度までは仕方がない。計算機的に、ある程度のコストがかかることは避けようがない。
だがここで問題となるのは、Objective-Cの動的な特性だ。Objective-Cではメソッドを呼び出すとき、それが実装されているかどうかは、呼び出し先に問い合わせるまで分からない。ということは、プロセス間通信を行うときも、まずメソッドが実装されているかを問い合わせて、その後実際の呼び出しを行う、という二重の手間がかかることになる。
これを回避するために、あらかじめ呼ばれる側が持っているであろうメソッドの一覧を、プロキシに設定しておくことができる。それには、setProtocolForProxy:を使う。
List 5. NSDistantObject
- (void)setProtocolForProxy:(Protocol*)aProtocol
このメソッドを使えば、呼ばれる側のメソッドをプロトコルの形であらかじめ設定できる。これにより、無駄な通信を減らすことができるのだ。
ちなみに、プロトコルについては、本連載の第9回「プロトコルが必要とされた背景とは? - なぜあえて静的な型を?」で取り上げたので、そちらも参照してほしい。
これは、NSProxyで実現されているProxyパターンの実際だ。一度プロキシを取得してしまえば、通常のオブジェクトとまったく同等に扱える。だが、その内部では、通信の効率化のために様々な工夫がされていることが分かるだろう。
提供:毎日キャリアバン ク
毎日キャリアバンクではITエンジニア出身のキャリアコンサルタントで形成する IT専門のチームを編成し、キャリアに応じた専任コンサルタントがご相談を承り ます。キャリアチェンジから市場価値の可能性、ご収入などの相談から面接のア ドバイスまでお気軽にご相談ください。求人情報誌や転職情報サイトなどで一般 に公開されていないような「急募求人案件」も随時ご紹介が可能です。まずはご 登録ください!