異なるオブジェクトのいずれか一方に対して、メソッド呼び出しを行いたいケースがあります。
NSString *a = @"a", *b = @"b";
unichar c;
if (a != b) {
c = [a characterAtIndex:0];
} else {
c = [b characterAtIndex:0];
}
printf("%c", c); // 'a'
条件によって対象のレシーバは変わっても、送信するメッセージは同一となるようなケースです。
コードをよりシンプルにする
上記のコードは条件演算子(?:
)を用いることで、以下のように簡潔に記述することもできますが、メッセージ式が二回出現してしまう点や、余計な一時変数を作らなければならなくなる点が難点です。
NSString *a = @"a", *b = @"b";
unichar c = a != b ? [a characterAtIndex:0] : [b characterAtIndex:0];
NSString *a = @"a", *b = @"b";
NSString *temp = a != b ? a : b;
unichar c = [temp characterAtIndex:0];
実は、プログラミング言語の仕組みを上手く活用することで、次のような記述が可能となります。
NSString *a = @"a", *b = @"b";
unichar c = [a != b ? a : b characterAtIndex:0];
このように、Objective-Cでは式の評価値に対するメッセージ転送も可能となっています。
戻り値に対するメッセージ転送
Objective-Cは、戻り値や評価結果に対するメッセージ呼び出しが可能です。
NSString *(^fn)(NSString *s) = ^(NSString *s) { return s; };
[fn(@"") length]; // 戻り値に対するメッセージ送信も可能
// この仕様はメソッドチェーンとしても応用されている
[[@"" substringToIndex:0] length];
ダークサイ度
条件演算子の評価値に対するメッセージ転送は、やりすぎない程度であれば、効果的なテクニックとなります。
ダークサイ度は★2つとします。メッセージ式の記法上、優先順位の問題にも遭遇しません。可読性が気になる場合は、条件演算子を括弧で囲うと良いでしょう。
[(a != b ? a : b) characterAtIndex:0];
適切に改行を入れると、読みやすくなる場合もあります。
[self.hoge
? self.foo
: self.bar
characterAtIndex:0];
状況によっては、一時変数を用いたほうが読みやすくなることもあります。
id tmp = _hoge ? _foo : _bar;
[tmp characterAtIndex:0];
このように、テクニックの利用に関する判断基準が曖昧な点や、記法にバラツキが発生しやすい点を考慮し、ダークサイ度は少し高めに設定しました。