UIActionSheet を Blocks で処理する

2010年7月28日水曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

iOS4から UIView のアニメーション関連のメソッドで Blocksが利用できるようになった。最近よく利用しているがこれは非常に便利。一方、UIActionSheet で不便を感じていたので試しに Blocksが使える実装を書いてみた。

使い方はこんなイメージ:
ActionSheetBlocksExtension*  sheet = [[ActionSheetBlocksExtension alloc] 
            initWithTitle:@"Action sheet sample" 
            didClick:^(UIActionSheet* actionSheet, NSInteger buttonIndex) {
                NSLog(@"[1] index %d: %@", buttonIndex, actionSheet);
            }
            cancelButtonTitle:@"Cancel"
            destructiveButtonTitle:@"Destructive" 
            otherButtonTitles:@"Other-11", @"Other-12", @"Other-13", nil];


アーキテクチャ


UIActionSheet のサブクラスを作り、このクラスで UIActionSheetDelegate を実装する。できればカテゴリで行きたかったが、Delegate先になるのと Blockを保持する必要があったのでサブクラスとした。


実装


今回は ActionSheetBlocksExtension という UIActionSheet のサブクラスを作った。
@interface ActionSheetBlocksExtension : UIActionSheet <UIActionSheetDelegate> {

 void (^didClickBlock_)(UIActionSheet*, NSInteger);
}

- (id)initWithTitle:(NSString *)title
     didClick:(void (^)(UIActionSheet*, NSInteger))block
  cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle
  otherButtonTitles:(NSString *)firstOtherTitle,...;

@end

didClickBlock_ は引数で渡される Block を格納するためのメンバ変数。

実装:
#pragma mark -
#pragma mark Initialization & deallocation
- (id)initWithTitle:(NSString *)title
     didClick:(void (^)(UIActionSheet*, NSInteger))block
  cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle
 otherButtonTitles:(NSString *)firstOtherTitle,...
{
 self = [super initWithTitle:title
        delegate:self
     cancelButtonTitle:nil
   destructiveButtonTitle:nil
     otherButtonTitles:nil];


 if (self) {
  didClickBlock_ = [block retain];

  int index = 0;
  
  if (destructiveButtonTitle) {
   [self addButtonWithTitle:destructiveButtonTitle];
   self.destructiveButtonIndex = index;
   index++;
  }
  
  if (firstOtherTitle) {
   [self addButtonWithTitle:firstOtherTitle];
   index++;
 
   va_list args;
   va_start(args, firstOtherTitle);
   NSString* title;
   while (title = va_arg(args, NSString*)) {
    [self addButtonWithTitle:title];
    index++;
   }
   va_end(args);
  }
  
  [self addButtonWithTitle:cancelButtonTitle];
  self.cancelButtonIndex = index;
 }
 return self;
}

- (void) dealloc
{
 [didClickBlock_ release];
 [super dealloc];
}

#pragma mark -
#pragma mark UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
 didClickBlock_(actionSheet, buttonIndex);
}

特に難しいことはやっていない。初期化で渡された blockを didClickBlock_ へ格納しておき、ボタンが押された時に呼び出している。

UIActionSheet のサブクラスの初期化については前回取り上げたのでそちらを参照のこと。



サンプル


これを組み込んだサンプルを作ってみた。呼び出し側のコードはこんな感じ。
- (IBAction)openSheet1:(id)sender
{
 ActionSheetBlocksExtension*  sheet = [[ActionSheetBlocksExtension alloc] 
            initWithTitle:@"Action sheet sample" 
            didClick:^(UIActionSheet* actionSheet, NSInteger buttonIndex) {
             NSLog(@"[1] index %d: %@", buttonIndex, actionSheet);
            }
            cancelButtonTitle:@"Cancel"
            destructiveButtonTitle:@"Destructive" 
            otherButtonTitles:@"Other-11", @"Other-12", @"Other-13", nil];
    [sheet autorelease]; 
    [sheet showInView:self.view];
}
Blocks内の処理は、押されたボタンのindexとUIActionSheetのインスタンスをデバッグ出力している。

さて実行してみよう。テスト用に3つの UIActionSheet を作るようにしてみた。
UIActionSheetの表示

ボタンを押すと Blocksで定義したコードが呼び出されているのがわかる。
[67822:207] [1] index 4: <ActionSheetBlocksExtension: 0x5d14ab0;
 baseClass = UIActionSheet; frame = (0 124; 320 336); opaque = NO;
 layer = <CALayer: 0x5d0fa80>>


ソースコード


GitHubからどうぞ。
ActionSheetUsingBlocks at 2010-07-27 from xcatsan's iOS-Sample-Code - GitHub


参考情報


Blocks Programming Topics: Getting Started with Blocks
iPhone Dev Center 提供の Blocks解説



その他


Blocks は不慣れなので問題があるかもしれません。ツッコミがあれば是非コメントにどうぞ。

なお @marvelph @gnue のツイートが参考になりました。ありがとうございました。

Responses

Leave a Response

人気の投稿(過去 30日間)