8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-12-31

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

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

基本の型

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

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

typedef

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

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

メソッド引数

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

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

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

プロパティ宣言

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

Blocksの実装部分

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

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

サンプル

typedef

// 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のカテゴリとして実装

メソッド引数宣言部分

// 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プロパティを抽出するサンプル

ダミーデータ準備

// 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];
}

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

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

ログ出力


// 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


- (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は、基本の型、メソッド引数として利用した場合の型、実装の型の3つが存在するようだ。
ひとまず、実装の型はXcodeの補完に任せるとして、基本の型、メソッド引数として利用した場合の型の
2つを覚えれば実装可能だと思います。

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

参考

10分でおぼえるBlocksの書き方

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?