yaakaito.org

Flow.jsをObjective-Cに移植してみた

JavaScript, Objective-C

こんにちは!うきょーです! Flow.js というJavaScriptのライブラリを見て、面白いなーと思ったのでObjective-Cでも似たようなことが出来るようにしてみた。junctionとforkは(まだ)実装してないので、完全な移植ではないです。 コードも適当なので遊び程度に見ていただければ。 ところで英語全然書けないので誰か「Natural English」ってプルリクをください。

Flow.m

名前はまんま、一応Cocoapodsにも入れてはいるのでCocoapods使ってる人は

1
pod 'Flow.m'

で使える。

出来ること

といっても、基本的には本家と同じなので、本家のスライドの方が詳しいのでそちらを参照していただきたく。 ただ微妙に仕様が違うところもある感じなので流しで書いておく。

基本的な使い方

FMFlowのオブジェクトを作る時に、waitscompletionBlockを渡す。 FMFlowのオブジェクトにはpassってメソッドが生えていて、これを呼び出すとカウンタが一個づつあがる。 呼び出した回数がwaitsに達したら、completionBlockが呼び出される。

1
2
3
4
5
6
FMFlow *flow = [FMFlow flowWithWaits:2 completionBlock:^(NSError *error, FMArguments *arguments) {
    NSLog(@"Flow!");
}];

[flow pass];
[flow pass]; // Flow!

extends

処理待機数を増やす、増える方向だけ。

1
2
3
4
5
6
7
8
FMFlow *flow = [FMFlow flowWithWaits:1 completionBlock:^(NSError *error, FMArguments *arguments) {
    NSLog(@"Flow!");
}];

[flow extend:1];

[flow pass];
[flow pass];  // Flow!

arguments

本家に合わせる為に若干無理してるんだけど、passWithValue:passWithValue:forKey:で渡せるし、インデックスかキーか好きなほうでどうぞ。

1
2
3
4
5
6
7
8
9
FMFlow *flow = [FMFlow flowWithWaits:2 completionBlock:^(NSError *error, FMArguments *arguments) {

    NSLog([arguments argumentAtIndex:0]); // HOGE
    NSLog([arguments argumentAtIndex:1]); // FUGA
    NSLog([arguments argumentForKey:@"fuga"]); // FUGA
}];

[flow passWithValue:@"HOGE"];
[flow passWithValue:@"FUGA" forKey:@"fuga"];

missとmissable

失敗可能回数の設定と、失敗の通知

1
2
3
4
5
6
7
8
FMFlow *flow = [FMFlow flowWithWaits:1 completionBlock:^(NSError *error, FMArguments *arguments) {
    NSLog(@"Flow!");
}];

[flow missable:1];

[flow miss]; // 1回は許可してるので問題ない
[flow pass]; // Flow!

失敗可能回数を超えた時は

1
2
3
4
5
6
7
8
9
10
11
12
FMFlow *flow = [FMFlow flowWithWaits:2 completionBlock:^(NSError *error, FMArguments *arguments) {
    // error がこんな感じで渡ってくる
    // error.domain : org.yaakaito.flow
    // error.code   : kFMErrorCodeFailure
    NSLog([arguments argumentAtIndex:0]); // ここまでに渡した引数は渡ってくる 
}];

[flow missable:1];

[flow miss];
[flow passWithValue:@"HOGE"];
[flow miss]; // 失敗したのでCompletionBlockを呼び出す

exit

強制終了。これはちょっと本家と違って、userInfoを渡すと、CompletionBlockerror.userInfoに入ってくるようになってる。

1
2
3
4
5
6
7
8
FMFlow *flow = [FMFlow flowWithWaits:1 completionBlock:^(NSError *error, FMArguments *arguments) {
    // error.domain : org.yaakaito.flow
    // error.code   : kFMErrorCodeExit
    NSLog([[error userInfo] objectForKey:@"msg"]); // えらー

}];

[flow exit:@{ @"msg" : @"えらー"}];

こんな感じです、残りはまた今度・・・

ところで

AppCode2.0のDarculaテーマは、見やすいのでおすすめです。

あああと非同期テストが必要になったわけなんですが、Cocoapods見てても、SenTestingKit+Asyncみたいなのはみるんだけど単純なモジュールねーなーみたいな。 みんなSenTestingKit用のスーパークラス作るのかなーと思った。 僕は別にちょっと待っててくれればいいだけなので、べつにただのオブジェクトでもいいわってなって、こういうの作った。作ったというか、元から他のコードで使ってたやつをpod化しただけ。 なんかwaitForTimeout:くらいしか使わんし、それで十分やろ、とか思うので、それしか作ってない。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)testAsyncMethod
{

  // Create instance.
  AsyncTestSupporter *asyncTest = [[AsyncTestSupporter alloc] init];

  // Prepare for asynchronous call.
  [asyncTest prepare]:

  __weak AsyncTestSupporter *that = asyncTest;
  // Call asynchronous method.
  [object asyncMethod:^() { // Completion blocks.
    // Wait for notify with timeout seconds.
    [that waitForTimeout:10];
  }];

  // Notify state if completed asynchronous method.
  [asyncTest notify:notify:kAsyncTestSupporterWaitStatusSuccess];

}