Objective-C
Xcode
switch

Swiftニモマケズ、NSStringデSwitch構文ヲ書ク

More than 3 years have passed since last update.


SwiftではSwitch構文で文字列が使えるようだが

Objective-CにはObjective-Cの良さがあると思う。C由来のゴタゴタやしがらみ、ややこしさ、汚さをフル活用すれば出来ないことはない・・・と思う。


StackOver風呂でいい記事を見つけた

http://goo.gl/LBeX77

に書いてあるんだが

#define CASE(str) if ([__s__ isEqualToString:(str)]) 

#define SWITCH(s) for (NSString *__s__ = (s); ; )
#define DEFAULT

SWITCH (string) {
CASE (@"AAA") {
break;
}
CASE (@"BBB") {
break;
}
CASE (@"CCC") {
break;
}
DEFAULT {
break;
}
}

とすればいいらしい。

実際に使ってみたがエレガントだと思う。

簡単にコードを読んでみるとSWITCHがfor文に置き換えられることで、実際のbreakを使えるようにし、なおかつSWITCHで比較元となる文字列を変数にうまく定義している。


改良1

しかし上記のコードだとDEFAULTを書き、なおかつそこでbreakしてやらないとfor文で回り続ける。

これだと実際のswitch構文の仕組みと挙動が異なる。switchとはフォールダウンすることはあっても頭に戻ることはないのだ。

(しかし今回のSWITCHはisEqualToString:をifがその都度確認している為、フォールダウンはできない。何かスマートに実現する方法はないだろうか?)まあC#でもフォールダウンは言語仕様上出来ないから、この件も「仕様」で片付けていいかな・・

なので少し改めてみた。

#define CASE(str) if ([__s__ isEqualToString:(str)])

#define SWITCH(s) for (NSString *__s__ = (s); __s__; __s__ = nil)
#define DEFAULT

こうしておくことで1周し終わればforの継続条件が成り立たなくなり2周目が回ることはないだろう。


改良2

さらに改良1を改良してみる。

しかし改良2は好みが分かれると思う。

#define _STRINGIZE(x) #x

#define __STRINGIZE(text) @ _STRINGIZE(text)
#define CASE(str) if ([__s__ isEqualToString:(__STRINGIZE(str))])
#define SWITCH(s) for (NSString *__s__ = (s); __s__; __s__ = nil)
#define DEFAULT

こうすることで次のような記述が可能になる。

SWITCH (string) {

CASE (AAA) {
break;
}
CASE (BBB) {
break;
}
CASE (CCC) {
break;
}
DEFAULT {
break;
}
}

NSStringを@"AAA"と書かずAAAと記述でき個人的にはブラボーだと思うが、きっとこの辺は好き嫌いがあると思う。


もし良ければIDEにスニペッドの登録を。


スニペッド(strsw)

#define _STRINGIZE(x) #x

#define __STRINGIZE(text) @ _STRINGIZE(text)
#define CASE(str) if ([__s__ isEqualToString:(__STRINGIZE(str))])
#define SWITCH(s) for (NSString *__s__ = (s); __s__; __s__ = nil)
#define DEFAULT