UIAlertViewとUIActionSheetをblocksで使いやすくする

UIAlertViewやUIActionSheetはdelegateで選択結果を取得して処理を分岐します。このdelegateでというのが結構面倒ですが、iOS4からはblocksが利用できるので、blocksを利用すればUIAlertViewをつくると同時にボタンに対応する動作も記述できて使いやすくなります。

ネット上にはblocksでの拡張情報がいくつかありますが、以下がネットの情報を元に私が作成したblocks版UIAlertViewとUIActionSheetです。

CTAlertView.h

#import <UIKit/UIKit.h>
 
@class CTAlertView;
 
typedef void (^CTAlertViewButtonCallback)(CTAlertView *alertView, NSInteger index);
 
@interface CTAlertView : UIAlertView <UIAlertViewDelegate> {
@private
    void (^willPresentCallback_)(CTAlertView *);
    void (^didPresentCallback_)(CTAlertView *);
    void (^willDismissCallback_)(CTAlertView *, NSInteger);
    void (^didDismissCallback_)(CTAlertView *, NSInteger);
 
    NSMutableArray *buttonCallbacks_;
}
 
- (id)initWithTitle:(NSString *)title
            message:(NSString *)message
  cancelButtonTitle:(NSString *)cancelButtonTitle;
 
-(void)addButtonWithTitle:(NSString*)title callback:(CTAlertViewButtonCallback)callback;
-(void)setCancelButtonCallback:(CTAlertViewButtonCallback)block;
-(void)setWillPresentCallback:(void (^)(CTAlertView *alertView))block;
-(void)setDidPresentCallback:(void (^)(CTAlertView *alertView))block;
-(void)setWillDismissCallback:(void (^)(CTAlertView *alertView, NSInteger index))block;
-(void)setDidDismissCallback:(void (^)(CTAlertView *alertView, NSInteger index))block;
 
@end

CTAlertView.h

#import "CTAlertView.h"
 
@interface CTAlertView ()
 
@property (nonatomic, retain) NSMutableArray *buttonCallbacks;
 
- (BOOL)hasCancelButton;
 
@end
 
@implementation CTAlertView
 
@synthesize buttonCallbacks=buttonCallbacks_;
 
- (id)initWithTitle:(NSString *)title
            message:(NSString *)message
  cancelButtonTitle:(NSString *)cancelButtonTitle
{
    self = [super initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];
    if (self) {
        self.delegate = self;
        self.buttonCallbacks = [NSMutableArray array];
        if ([self hasCancelButton]) {
            [self setCancelButtonCallback:^(CTAlertView *alertView, NSInteger index){}];
        }
    }
    return self;
}
 
- (void)dealloc
{
    [willPresentCallback_ release];
    [didPresentCallback_ release];
    [willDismissCallback_ release];
    [didDismissCallback_ release];
    self.buttonCallbacks = nil;
 
    [super dealloc];
}
 
-(void)addButtonWithTitle:(NSString*)title callback:(CTAlertViewButtonCallback)callback
{
    id obj = [NSNull null];
    if (callback) obj = [[callback copy] autorelease];
 
    [self addButtonWithTitle:title];
    [self.buttonCallbacks addObject:obj];
}
 
-(void)setCancelButtonCallback:(CTAlertViewButtonCallback)callback
{
    if (![self hasCancelButton]) return;
 
    if ([self.buttonCallbacks count] &gt; 0) {
        [self.buttonCallbacks removeObjectAtIndex:0];
    }
 
    [self.buttonCallbacks insertObject:[[callback copy] autorelease] atIndex:0];
}
 
-(void)setWillPresentCallback:(void (^)(CTAlertView *alertView))block
{
    [willPresentCallback_ release];
    willPresentCallback_ = [block retain];
}
 
-(void)setDidPresentCallback:(void (^)(CTAlertView *alertView))block
{
    [didPresentCallback_ release];
    didPresentCallback_ = [block retain];
}
 
-(void)setWillDismissCallback:(void (^)(CTAlertView *alertView, NSInteger index))block
{
    [willDismissCallback_ release];
    willDismissCallback_ = [block retain];
}
 
-(void)setDidDismissCallback:(void (^)(CTAlertView *alertView, NSInteger index))block
{
    [didDismissCallback_ release];
    didDismissCallback_ = [block retain];
}
 
- (BOOL)hasCancelButton
{
    return (self.cancelButtonIndex == 0);
}
 
#pragma mark -
#pragma mark UIAlertViewDelegate
 
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    id callback = [self.buttonCallbacks objectAtIndex:buttonIndex];
    if (![callback isMemberOfClass:[NSNull class]]) {
        ((CTAlertViewButtonCallback)callback)((CTAlertView *)alertView, buttonIndex);
    }
}
 
-(void)willPresentAlertView:(UIAlertView *)alertView
{
    if(willPresentCallback_) willPresentCallback_((CTAlertView *)alertView);
}
 
-(void)didPresentAlertView:(UIAlertView *)alertView
{
    if(didPresentCallback_) didPresentCallback_((CTAlertView *)alertView);
}
 
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if(willDismissCallback_) willDismissCallback_((CTAlertView *)alertView, buttonIndex);
}
 
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if(didDismissCallback_) didDismissCallback_((CTAlertView *)alertView, buttonIndex);
}
 
@end

CTActionSheet.h

#import <UIKit/UIKit.h>
 
@class CTActionSheet;
 
typedef void (^CTActionSheetButtonCallback)(CTActionSheet *actionSheet, NSInteger index);
 
@interface CTActionSheet : UIActionSheet <UIActionSheetDelegate> {
@private
    NSMutableArray *buttonCallbacks_;
    void (^willPresentCallback_)(CTActionSheet *);
    void (^didPresentCallback_)(CTActionSheet *);
    void (^willDismissCallback_)(CTActionSheet *, NSInteger);
    void (^didDismissCallback_)(CTActionSheet *, NSInteger);
}
 
- (id)initWithTitle:(NSString *)title;
 
- (void)addCancelButtonWithTitle:(NSString *)title callback:(CTActionSheetButtonCallback)callback;
- (void)addDestructiveButtonWithTitle:(NSString *)title callback:(CTActionSheetButtonCallback)callback;
- (void)addButtonWithTitle:(NSString *)title callback:(CTActionSheetButtonCallback)callback;
- (void)setWillPresentCallback:(void (^)(CTActionSheet *actionSheet))callback;
- (void)setDidPresentCallback:(void (^)(CTActionSheet *actionSheet))callback;
- (void)setWillDismissCallback:(void (^)(CTActionSheet *actionSheet, NSInteger index))callback;
- (void)setDidDismissCallback:(void (^)(CTActionSheet *actionSheet, NSInteger index))callback;
 
@end

CTActionSheet.m

#import "CTActionSheet.h"
 
@interface CTActionSheet ()
 
@property (nonatomic, retain) NSMutableArray *buttonCallbacks;
 
@end
 
@implementation CTActionSheet
 
@synthesize buttonCallbacks=buttonCallbacks_;
 
- (id)initWithTitle:(NSString *)title
{
    self = [super initWithTitle:title delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
    if (self) {
        self.delegate = self;
        self.buttonCallbacks = [NSMutableArray array];
    }
    return self;
}
 
- (void)dealloc
{
    self.buttonCallbacks = nil;
    [willPresentCallback_ release];
    [didPresentCallback_ release];
    [willDismissCallback_ release];
    [didDismissCallback_ release];
 
    [super dealloc];
}
 
- (void)addCancelButtonWithTitle:(NSString *)title callback:(CTActionSheetButtonCallback)callback
{
    NSUInteger index = [self.buttonCallbacks count];
    [self addButtonWithTitle:title callback:callback];
    self.cancelButtonIndex = index;
}
 
- (void)addDestructiveButtonWithTitle:(NSString *)title callback:(CTActionSheetButtonCallback)callback
{
    NSUInteger index = [self.buttonCallbacks count];
    [self addButtonWithTitle:title callback:callback];
    self.destructiveButtonIndex = index;
}
 
- (void)addButtonWithTitle:(NSString*)title callback:(CTActionSheetButtonCallback)callback
{
    id obj = [NSNull null];
    if (callback) obj = [[callback copy] autorelease];
 
    [self addButtonWithTitle:title];
    [self.buttonCallbacks addObject:obj];
}
 
-(void)setWillPresentCallback:(void (^)(CTActionSheet *actionSheet))callback
{
    [willPresentCallback_ release];
    willPresentCallback_ = [callback retain];
}
 
-(void)setDidPresentCallback:(void (^)(CTActionSheet *actionSheet))callback
{
    [didPresentCallback_ release];
    didPresentCallback_ = [callback retain];
}
 
-(void)setWillDismissCallback:(void (^)(CTActionSheet *actionSheet, NSInteger index))callback
{
    [willDismissCallback_ release];
    willDismissCallback_ = [callback retain];
}
 
-(void)setDidDismissCallback:(void (^)(CTActionSheet *actionSheet, NSInteger index))callback
{
    [didDismissCallback_ release];
    didDismissCallback_ = [callback retain];
}
 
#pragma mark -
#pragma mark UIActionSheetDelegate
 
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    id callback = [self.buttonCallbacks objectAtIndex:buttonIndex];
    if (![callback isMemberOfClass:[NSNull class]]) {
        ((CTActionSheetButtonCallback)callback)((CTActionSheet *)actionSheet, buttonIndex);
    }
}
 
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet
{
    if (willPresentCallback_) willPresentCallback_((CTActionSheet *)actionSheet);
}
 
- (void)didPresentActionSheet:(UIActionSheet *)actionSheet
{
    if (didPresentCallback_) didPresentCallback_((CTActionSheet *)actionSheet);
}
 
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (willDismissCallback_) willDismissCallback_((CTActionSheet *)actionSheet, buttonIndex);
}
 
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (didDismissCallback_) didDismissCallback_((CTActionSheet *)actionSheet, buttonIndex);
}
 
@end

使い方は

CTAlertView *alert = [[[CTAlertView alloc] initWithTitle:@"title" message:@"message" cancelButtonTitle:@"Cancel"] autorelease];
[alert setCancelButtonCallback:^(CTAlertView *alertView, NSInteger index) {
    // Cancel action
}];
[alert addButtonWithTitle:@"Foo" callback:^(CTAlertView *alertView, NSInteger index) {
    // Foo action
}];
[alert addButtonWithTitle:@"Bar" callback:^(CTAlertView *alertView, NSInteger index) {
    // Bar action
}];
[alert show];

のようにします。キャンセルタイトルは指定しなければキャンセルボタンは作成されません。また、キャンセルボタンコールバックを指定しなくても動作します。

CTActionSheetではキャンセルボタンの指定を- (void)addCancelButtonWithTitle:(NSString *)title callback:(CTActionSheetButtonCallback)callbackで行います。

また、テストは不十分なので、バグがあればコメントよろしくです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です