今更ながら覚えにくいBlocksの文法を復習してみる

Blocksを使うまでは、delegateを使って実装をしていたが、delegateだと呼び出し箇所と実行箇所が分離してしまい、可読性が悪くなることがある。

それにしても、Blocksは文法が覚えにくい自分の整理のために復習してみることにする。

## 基本の型

> 戻り値 (^Blocks名) (引数)

Blocks名の前に(^)キャレットがつくのが特徴のようです。

## typedef

> typedef 戻り値 (^Blocks名) (引数);

typedefを使うことでBlocksをまるっと変数の型の用に宣言することができる。


## メソッド引数

*正直これが覚えにくい*
Blocksが引数として利用されると形が変形します。

```objc
- (void)loadImageCompletion:(BOOL(^)(BOOL canceled))completion;
```

> 戻り値 (^Blocks名) (引数)　　※基本型
　↓
　↓ 名前を後ろへ切り出す　←メソッド引数名は最後にくるから
　↓
戻り値 (^) (引数)Blocks名
　↓
　↓ 引数の型となる範囲を( )で囲う　←メソッド標準の書き方
　↓
(戻り値 (^) (引数)) Blocks名

## プロパティ宣言

@property (copy) 戻り値 (^Blocks名) (引数)

## Blocksの実装部分

> ^戻り値 (引数) {...}

実装部分の場合は、Blocks名が不要なのは当然だが^（キャレット)が戻り値の前に移動する。
これも基本の型と異なる。但し、Xcodeの補完機能を使えば実装部分は勝手に補完されるので
正確に覚えておかなくても実装は可能だ。

## サンプル

### typedef

```objc
// typedef宣言
typedef BOOL (^compareNumber) (NSString *, NSNumber *);

// 実装
compareNumber equals = ^(NSString *string, NSNumber *number){
    if ([string isEqualToString:[number stringValue]]){
        return YES;
    }
    return NO;
};

// 利用
NSLog(@"result:%zd",equals(@"111",@111));
NSLog(@"result:%zd",equals(@"112",@111));
```

### 引数

javaScriptのmapのようなものを作ってみたいと思います。

**blocksメソッド引数利用の実装例**

ここではNSArrayのカテゴリとして実装

> メソッド引数宣言部分

```objc
// NSArray+Hoge.h
- (NSArray *)mapWithBlocks:(id(^)(id))blocks;

// NSArrary+Hoge.m 
- (NSArray *)mapWithBlocks:(id(^)(id))blocks
{
    NSMutableArray *results = [NSMutableArray array];
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        id value = blocks(obj);
        [results addObject:value];
    }];
    return results;
}

``` 

実際に使ってみます。

HogeEntityという型のEntityの配列からtitleプロパティを抽出するサンプル

> ダミーデータ準備

```objc
// HogeEntity.h
@interface HogeEntity : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *context;
@end

// ダミーデータ作成
self.array1 = [NSMutableArray array];
for (NSInteger i=0; i < 10; i++) {
   HogeEntity *entity = [HogeEntity new];
   entity.title = [NSString stringWithFormat:@"タイトル%zd",i];
   entity.context = [NSString stringWithFormat:@"本文%zd",i];
   [self.array1 addObject:entity];
}
```

> メソッド引数として実行している部分

```objc
// Blocks引数を使ってtitleを抽出して配列として出力
NSArray *results = [self.array1 mapWithBlocks:^id(HogeEntity *entity) {
    return entity.title;
}];
```

> ログ出力

```objc

// resultsの結果をログに出力
[results enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL *stop) {
        NSLog(@"[%zd]%@",idx,title);
    }];

// コンソール結果
2014-12-31 18:53:52.359 Test3[12509:4640980] [0]本文0
2014-12-31 18:53:52.359 Test3[12509:4640980] [1]本文1
2014-12-31 18:53:52.359 Test3[12509:4640980] [2]本文2
2014-12-31 18:53:52.359 Test3[12509:4640980] [3]本文3
2014-12-31 18:53:52.359 Test3[12509:4640980] [4]本文4
2014-12-31 18:53:52.359 Test3[12509:4640980] [5]本文5
2014-12-31 18:53:52.359 Test3[12509:4640980] [6]本文6
2014-12-31 18:53:52.360 Test3[12509:4640980] [7]本文7
2014-12-31 18:53:52.360 Test3[12509:4640980] [8]本文8
2014-12-31 18:53:52.360 Test3[12509:4640980] [9]本文9
```

## おまけ

javaScript風filter

```objc

- (NSArray *)filterWithBlock:(BOOL (^)(id))blocks
{
    NSMutableArray *results = [NSMutableArray array];
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if (blocks(obj)) {
            [results addObject:obj];
        }
    }];
    return results;
}

// タイトル4を除外
results = [self.array1 filterWithBlock:^BOOL(HogeEntity *entity) {
  if (![entity.title isEqualToString:@"タイトル4"]) {
    return YES;
  }
  return NO;
}];
    
[results enumerateObjectsUsingBlock:^(HogeEntity *entity, NSUInteger idx, BOOL *stop) {
   NSLog(@"[%zd]%@",idx,entity.title);
}];

// ログ
2014-12-31 19:32:34.608 Test3[13019:4659567] [0]タイトル0
2014-12-31 19:32:34.608 Test3[13019:4659567] [1]タイトル1
2014-12-31 19:32:34.608 Test3[13019:4659567] [2]タイトル2
2014-12-31 19:32:34.608 Test3[13019:4659567] [3]タイトル3
2014-12-31 19:32:34.609 Test3[13019:4659567] [4]タイトル5
2014-12-31 19:32:34.609 Test3[13019:4659567] [5]タイトル6
2014-12-31 19:32:34.609 Test3[13019:4659567] [6]タイトル7
2014-12-31 19:32:34.609 Test3[13019:4659567] [7]タイトル8
2014-12-31 19:32:34.609 Test3[13019:4659567] [8]タイトル9

```

## まとめ

Blocksは、基本の型、メソッド引数として利用した場合の型、実装の型の３つが存在するようだ。
ひとまず、実装の型はXcodeの補完に任せるとして、基本の型、メソッド引数として利用した場合の型の
２つを覚えれば実装可能だと思います。

それでは、皆様良いお年をお迎えください〜

## 参考

[10分でおぼえるBlocksの書き方](http://cocoadays.blogspot.jp/2013/07/10blocks.html)