WEBサービス創造記

WEBサービスを作ったり保守したりしてる人のメモブログです。

Objective-Cのメッセージ式について

      2015/01/14

メッセージ式とは

Objective-Cではメッセージ式と呼ばれる式をメソッドの呼び出しに使っています。

以下のHello World!のコードでは` [greeter sayHello];`の部分がメッセージ式に当たります。

#import "Greeter.h"

int main(void) {
  id greeter = [Greeter alloc];
  [greeter sayHello];

  return 0;
}

Objective-Cのソースコードを見てみると、このようなメッセージ式が多く見られることと思います。
他のプログラミング言語でのメソッド実行は`greeter.sayHello();`のような形式である場合が多いですが、それらとは書式が大きく異なるため、最初は奇異に感じるかもしれません(※他言語の経験者である自分はそうでした)。

メッセージとメソッドの違い

[greeter sayHello] ≠ greeter.sayHello();

メッセージ式`[greeter sayHello]`は厳密には`greeter.sayHello();`のようなメソッド実行の式とは区別されます。

`greeter.sayHello();`はgreeterのメンバであるsayHelloメソッドにアクセスするものであるのに対して、`[greeter sayHello]`は、greeterにsayHelloというメッセージを送っているという解釈となります。
`[greeter sayHello]`の場合、メッセージを受け取っているgreeterはレシーバと呼ばれます。sayHelloの部分はメッセージと呼ばれ、実行してほしいメソッドを伝えます。

オブジェクトはメッセージを受け取るとその内容に応じて処理を行い、結果を返します。つまり、受け取ったメッセージに対応するメソッドを呼び出すわけです。

`greeter.sayHello();`のような式ではメンバに指定したメソッドがないとエラーとなりますが、Objective-Cではもし対応するメソッドの実装がなかった場合は別のオブジェクトに処理を委譲(デリゲート)する仕組みがあります(※1)。
この点がメッセージとメソッドの大きな違いであると言えます。

また、メッセージ式を実行するオブジェクトはレシーバとは相対的に、センダー(送り手)と呼ばれます。

メッセージキーワード

引数を持つメソッドをメッセージ式で呼び出すときは、第二引数からはメッセージキーワードというラベルに相当するものを付与することができます。

例えば、Gameというクラスに以下のようなstartというメソッドが定義されているとします。

@interface Game : NSObject
- (void) start:(NSString *)argWhen
         at:(NSString *)argAt
         level:(int)argLevel;
@end

このメソッドをメッセージ式では以下のように呼び出すことができます。

id game = [Game alloc];
[game start:@"now" at:@"second stage" level:7];

この場合、”at”と”level”がメッセージキーワードです。メッセージキーワードは組する引数にどんな意味かを表すことができるます。
したがってメッセージキーワードを使うことでメッセージ式全体が英文として読み下せるようになっているのがわかります。

注意が必要なのは、メッセージキーワードが付加されるのは第二引数からだということです。
この例だと第一引数である”argWhen”にはメッセージキーワードがついておらず、”メソッド名:argWhenの実引数”(start:@”now”)となっています。
この点は慣れていないと混乱しやすい(自分は最初見たとき混乱しました)と思うので気をつけた方がいいかもしれません。

メッセージキーワードは変数と同じように命名することができます。小文字から書き始め、キャメル記法で書く(複数の単語がある場合は単語の先頭文字を大文字にしてつなぐ。”sayHellow”など)のが慣習のようです。
メソッド名やメッセージキーワードもメッセージ式にしたときに英文として意味をなすように命名すると、コードの可読性があがっていい感じになると思います。

他のプログラミング言語ではメソッド実行に`game.start(“now”, “second stage”, 7)`と書くことがありますが、それに比べると可読性が高いのではないかと自分は思います。

サンプルコード

Hello World!のコードを、上記で説明したメッセージ式の性質に従ってリファクタリングしたのが以下のコードです。一応置いておきます。

Greeter.h

#import <Foundation/Foundation.h>

@interface Greeter : NSObject
- (void) say:(NSString *)whenString
         to:(NSString *)toString;
@end

Greeter.m

#import "Greeter.h"

@implementation Greeter

- (void) say:(NSString *)whenString to:(NSString *)toString{
  printf("%s %s.\n", [whenString UTF8String], [toString UTF8String]);
}

@end

main.m

#import "Greeter.h"

int main(void) {
  id greeter = [Greeter alloc];
  [greeter say:@"Hello" to:@"World"];

  return 0;
}

謝辞

このページを作成するにあたって以下のWebページを参考にさせていただきました。ありがとうございます。

こたつつきみかん » なぜ Objective-C はメッセージ式なのか
Selection 9: Objective-C(メッセージ)

注釈

※1

ここではメッセージとメソッドの違いに焦点をあてるのでどのようなコードでデリゲートを行うかなどの技術的な点は割愛します。

 - Objective-C ,