最近、社内で iBeacon の全社向け勉強会をしました happy_ryo です。
今回は Objective-C の反復処理についてです。
Objective-C の反復処理には、幾つかの種類があることは皆さんご存じだと思いますが、今回は他の言語を経験していると見逃しがちな書き方である、ブロックを利用した書き方もあわせて紹介したいと思います。
Objective-C 以外でも見かける書き方
まずは普通の書き方
他の言語を書いていてもよく見かけるものです。
1 2 3 |
for (int j = 0; j < array.count; j++) { // 処理を書く } |
高速反復処理
これも、構文こそ違えどよく見かけるものです。
NSFastEnumeration プロトコルに準拠しているクラスのインスタンスであれば高速反復処理を利用することができます。この書き方で配列を処理した場合、インデックスが手に入らないことがネックになることがあります。
1 2 3 |
for (NSString *item in array) { // 処理を書く } |
配列を逆順に処理したい場合は以下のようになります。
1 2 3 |
for (NSString *item in array.reverseObjectEnumerator) { // 処理を書く } |
自分で for ループを工夫して書くよりも、確実ですね。
NSDictionary の場合は以下のようになります。
1 2 3 4 |
for (id key in dictionary){ id obj = [dictionary valueForKey:key]; // 処理を書く } |
Objective-C 以外では見なかったりもする書き方
表現が曖昧なのは、全ての言語において以下のような書き方が実装されていないわけでは無いためです。
NSEnumerator を使う書き方
この書き方は、高速反復処理が実装される以前に用意された物なので、現代では余り使わないかも知れませんが、Foundation フレームワークの全てのコレクション系のクラスで利用することができます。 nextObject を呼び出す度に、次の要素があればそのインスタンスを、次の要素がなければ nil を返すことに注意する必要があります。
1 2 3 4 5 |
NSEnumerator *enumerator = array.objectEnumerator; id obj; while ((obj = enumerator.nextObject) != nil) { // 処理を行う } |
逆順だと、以下のようになります。
1 2 3 4 5 |
NSEnumerator *enumerator = array.reverseObjectEnumerator; id obj; while ((obj = enumerator.nextObject) != nil) { // 処理を行う } |
objectEnumerator の代わりに reverseObjectEnumerator を用いることで、逆順の反復処理を書くことが出来ます。
ブロックを利用した書き方
観測範囲の問題かも知れませんが、あまりこの書き方で書かれたコードを見ません。他の言語を経験している場合、何かの本で読むか、偶然出会うか、まじめにドキュメントを読むかをしないと、こういった書き方があることに気付かないせいかもしれません。覚えてしまえば便利な書き方なので、使えそうな所で積極的に利用して手に覚えさせてしまえば良いと思います。
1 2 3 4 5 6 7 8 9 |
// id型が指定されている obj の型が確定しているのであれば、その部分をオーバーライドして該当の型に書き換えても良い [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { // 処理を書く if (hogeStop) { // *stop を YES にするとループを抜ける *stop = YES; } }]; |
この書き方のメリットは要素だけでは無く、インデックスの情報も同時に手に入ることです、対象が NSDictionary の場合は要素とキーの情報が同時に手に入ります。また、 *stop を YES にすることで、安全に反復処理を終了させることも出来ます、これは他の反復処理でいうところの break; に相当しますが *stop が YES になった後も実行中の反復処理が実行される点が異なります。
この書き方では、オプションを指定することで反復処理の振る舞いを変化させることが出来、以下がその例になります。
1 2 3 |
[array enumerateObjectsWithOptions:(NSEnumerationReverse | NSEnumerationConcurrent) usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { // 処理を書く }]; |
NSEnumerationReverse は配列を逆順で処理するためのオプションで、NSEnumerationConcurrent は反復処理を平行して行うためのオプションです。NSEnumerationConcurrent による反復処理の容易な平行処理化が、この書き方の最大の特徴では無いかと思います。
少し、普通の for 文よりも長くなってしまいますが IDE を使っていれば些細な差なので、一般的なブロック利用時の注意点を守りつつ積極的に利用しましょう。
アライドアーキテクツでは、社内社外問わず勉強会をやってみたいエンジニアを募集しています。
営業→工場で作業→Word&Excel→Java→shellscript→Java→PHP→Python→Objective-C→Swift→PHP→JavaScript→ベトナム 子会社CTO→本社CTO←イマココ