統計情報(30日間)


最新情報をツイート

人気の投稿

シンプルだが強力そしてエレガントなコードのシーケンサ

このエントリーをはてなブックマークに追加

ソースコードがヘッダやコメントを入れても100行にも満たない無駄の無いコード。それでいて十分な機能。



ここでいうシーケンサとは、あらかじめ登録した複数の処理を順番に実行する仕組みのこと。ネットワークアクセスやユーザインタラクションは基本非同期な処理になるが、特定の順番で同期的に処理を行いたい場合がある。シーケンサはそんな用途で利用できる。

単純な例
Sequencer *sequencer = [[Sequencer alloc] init];
[sequencer enqueueStep:^(id result, SequencerCompletion completion) {
    NSLog(@"This is the first step");
    completion(nil);
}];
[sequencer enqueueStep:^(id result, SequencerCompletion completion) {
    NSLog(@"This is another step");
    completion(nil);
}];
[sequencer enqueueStep:^(id result, SequencerCompletion completion) {
    NSLog(@"This step is going to do some async work...");
    int64_t delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        NSLog(@"finished the async work.");
        completion(nil);
    });
}];
[sequencer enqueueStep:^(id result, SequencerCompletion completion) {
    NSLog(@"This is the last step");
    completion(nil);
}];
[sequencer run];
completionの引数が次のステップの引数 result として渡っていく。

ネットワークアクセスの例
Sequencer *sequencer = [[Sequencer alloc] init];
[sequencer enqueueStep:^(id result, SequencerCompletion completion) {
    NSURL *url = [NSURL URLWithString:@"https://alpha-api.app.net/stream/0/posts/stream/global"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        completion(JSON);
    } failure:nil];
    [operation start];
}];
[sequencer enqueueStep:^(NSDictionary *feed, SequencerCompletion completion) {
    NSArray *data = [feed objectForKey:@"data"];
    NSDictionary *lastFeedItem = [data lastObject];
    NSString *cononicalURL = [lastFeedItem objectForKey:@"canonical_url"];

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:cononicalURL]];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        completion(responseObject);
    } failure:nil];
    [operation start];
}];
[sequencer enqueueStep:^(NSData *htmlData, SequencerCompletion completion) {
    NSString *html = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
    NSLog(@"HTML Page: %@", html);
    completion(nil);
}];
[sequencer run];
最初のステップでJSONを取得し、次にURL情報から HTMLを取得。最後にそれをログに表示。シーケンサを使うとデリゲートチェーンやblocksの多段ネストの必要が無くなり見通し良いコードが書ける。なかなかいい感じ。

Leave a Reply