はじめに
「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
----
その時、
**「BlocksをPropertyとして持たせると良いですよ」**
と教えてもらいました。
そう。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]; });```
先頭の `[[[[` が無くなった!
・・まあ、ただそれだけです。でもこっちの方が書きやすいし、読み易いでしょ?(^^
ポイントポイントでこういう書き換えもありかなぁ、と思いました。
注意
===
たぶん、この書き換えで問題ないと思うのですが間違ってたらすみません。。