LoginSignup
29
29

More than 5 years have passed since last update.

Objective-CでDeferred/PromiseでMethod Chainを書くときのTips

Last updated at Posted at 2013-11-15

はじめに

「Objective-Cの文法とMethod Chainって致命的に相性悪いよね」というのを解消するTipsです。
さっき社内の後輩に教えてもらって感動したので投稿します。

問題点

最近かじり始めたDeferred/PromiseをObjective-Cでも使いたいと探していて、とりあえず CocoaPodsでInstallできる

OMPromises https://github.com/b52/OMPromises

というのを使っていました。
Promiseの考え方は、Webのみならず、通信や非同期Methodが多用されるiOS/Androidアプリでもとても重宝しそうです。

で、このOMPromisesですが、動作上はとりあえず問題無さそうなのですが、JavaScriptのようにMethodChainを行おうとすると、こんな感じになります。

return [[[[self firstAPICall]     then:^id(YREModelUser *user)    {        user.name = name;        return [self secondAPICall:user];    }]     fulfilled:^(id result)    {        [self storeResult: result];    }]     failed:^(NSError *error)    {        NSLog(@"%@", error);        [self notifyError: error];    }];```

これがどうにも気持ち悪い。最初の `[[[[` っていうカッコは何だ! 戦場ヶ原ひたぎじゃあるまいし。
この部分に処理を追加したり削除すると、最初の `[[[` の数も調整しないといけない。コンパイルエラーですぐにわかるから良いけど楽しくない。
やはり、ObjectiveCではMethodChainではなく、変数に代入して繋げていくしかないのかな、と思っていました。

Tips
----

その時、
**BlocksPropertyとして持たせると良いですよ」**
と教えてもらいました。

そう。Property .(ドット) で繋げられるし、Blocksの呼び出しは () で行けるので、この文法的なやるせなさを解消してくれるのです。


解法
-------

OMPromise Class Category として幾つか機能を追加します。

```objectivec:OMPromise+MethodChain.h
#import "OMPromise.h"

typedef id   (^ThenHandler)(id result);
typedef void (^DoneHandler)(id result);
typedef void (^FailHandler)(NSError *error);

typedef OMPromise *(^ThenBlock)(ThenHandler thenHandler);
typedef OMPromise *(^DoneBlock)(DoneHandler doneHandler);
typedef OMPromise *(^FailBlock)(FailHandler failHandler);

@interface OMPromise (MethodChain)
@property (readonly) ThenBlock then2;
@property (readonly) FailBlock fail;
@property (readonly) DoneBlock done;
@end
OMPromise+MethodChain.m
#import "OMPromise+MethodChain.h"

@implementation OMPromise (MethodChain)
- (ThenBlock)then2
{
    ThenBlock block = ^OMPromise *(ThenHandler handler) {
        return [self then:handler];
    };
    return block;
}

- (FailBlock)fail
{
    FailBlock block = ^OMPromise *(FailHandler handler) {
        return [self failed:handler];
    };
    return block;
}

- (DoneBlock)done
{
    DoneBlock block = ^OMPromise *(DoneHandler handler) {
        return [self fulfilled:handler];
    };
    return block;
}
@end

then2とかいうやっつけな名前になっているのは、とりあえず目をつぶって下さい。
こうしておいて、 #import "OMPromise+MethodChain.h" としておくと、先ほどのコードが以下のようになります。

return [self firstAPICall]    .then2(^id(YREModelUser *user)    {        user.name = name;        return [self secondAPICall:user];    })     .done(^(id result)    {        [self storeResult: result];    })    .fail(^(NSError *error)    {        NSLog(@"%@", error);        [self notifyError: error];    });```


先頭の `[[[[` が無くなった!

・・まあ、ただそれだけです。でもこっちの方が書きやすいし、読み易いでしょ?(^^
ポイントポイントでこういう書き換えもありかなぁ、と思いました。

注意
===

たぶん、この書き換えで問題ないと思うのですが間違ってたらすみません。。

29
29
1

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