sos の 作業メモ

プログラミングや英会話学習、マイルや旅行、日常生活など。最近はWebFormなASP.NETのお守りがお仕事です。

日々の生活にhappyをプラスする|ハピタス Gポイント

UIAlertViewのボタンイベントをDelegateじゃなくてBlocksで処理したい

UIAlertViewでアラートを表示するのは簡単ですが、ボタンが押された時のイベントを受け取るのに毎回Delegateを定義するのはめんどくさいですよね。

仕方がないので、Blockを引数にできるクラスをUIAlertViewから派生させて作ってみました。

まずはインターフェース。 UIAlertViewのinitWithTitleをベースに、cancelイベント(キャンセルボタンではなく、モードレスでHomeが押された時に発生すると読んだような記憶がありますが、正確には憶えていません)と、ボタン押し下げイベントのハンドラをBlockで渡すようにしてます。ついでに、cancelButtonTitleは無しにして、全部buttonTitlesで定義するようします。並び順は自分で管理しますよってことで。

@interface AlertViewWithBlock : UIAlertView <UIAlertViewDelegate>

- (id)initWithTitle:(NSString *)title message:(NSString *)message cancelHandler:(void (^)(UIAlertView* view))cancelHandler buttonHandler:(void (^)(UIAlertView* view, NSInteger index))buttonHandler buttonTitles:(NSString *)buttonTitles, ... NS_REQUIRES_NIL_TERMINATION;

@end

実装側はこんな感じ。Objective-Cでも可変引数はCと同じで良いみたい。Blockの型とか変数宣言とか、ちゃんと理解できるまでかなり混乱しました。

@implementation AlertViewWithBlock
{
    void (^varbuttonHandler)(UIAlertView*, NSInteger);
    void (^varcancelHandler)(UIAlertView*);
}

- (id)initWithTitle:(NSString *)title message:(NSString *)message cancelHandler:(void (^)(UIAlertView*))cancelHandler buttonHandler:(void (^)(UIAlertView*, NSInteger))buttonHandler buttonTitles:(NSString *)buttonTitles, ...
{
    self = [self initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
    if(self){
        va_list argumentList;
        if(buttonTitles){
            [self addButtonWithTitle:buttonTitles];
            va_start(argumentList, buttonTitles);
            id eachObj;
            while ((eachObj = va_arg(argumentList, id))){
                [self addButtonWithTitle: eachObj];
            }
            va_end(argumentList);
        }
        varcancelHandler = cancelHandler;
        varbuttonHandler = buttonHandler;
    }
    return self;
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if(varbuttonHandler){
        varbuttonHandler(alertView,buttonIndex);
    }
}

- (void)alertViewCancel:(UIAlertView *)alertView{
    if(varcancelHandler){
        varcancelHandler(alertView);
    }
}

@end

そして使い方はこんな感じ

AlertViewWithBlock* alert = [[AlertViewWithBlock alloc] initWithTitle:@"タイトル" message:@"メッセージ" cancelHandler:^(UIAlertView* alertView){
    NSLog(@"Cancel");
} buttonHandler:^(UIAlertView* alertView, NSInteger buttonIndex){
    NSLog(@"Pushed %d Button",buttonIndex);
} buttonTitles:@"キャンセル",@"OK", nil];
[alert show];

3時間くらい時間かけちゃいましたが、これで便利になるのかどうかは微妙な感じです。