@implementation MyClass
- (void)showAlert
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title"
message:@"Message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Other Button", nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
// Do something.
}
@end
これを GCD みたいに block を使用して処理したいと思ったので調べてみたところ、実装できたので公開する。
まず UIAlertView をサブクラス化し、インスタンス変数 _completionHandler を追加する。
buttonIndex は押下されたボタンを引数として渡すためのもの。
@interface MyAlertView : UIAlertView {
void (^_completionHandler)(NSInteger buttonIndex);
}
- (void)showWithCompletionHandler:(void(^)(NSInteger buttonIndex))_completionHandler;
@end
実装は次のとおり。
@implementation MyAlertView
- (void)showWithCompletionHandler:(void(^)(NSInteger buttonIndex))completionHandler
{
// completionHandler を copy し、アラートを表示する。
_completionHandler = [completionHandler copy];
[self show];
}
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
{
// アラートを閉じ、 _completionHandler を実行する。
[super dismissWithClickedButtonIndex:buttonIndex animated:animated];
_completionHandler(buttonIndex);
}
- (void)dealloc
{
// _completionHandler を解放する。
[_completionHandler release];
[super dealloc];
}
@end
通常、 block をコピーする必要はないが、今回はその必要がある。
通常は、ブロックをコピー(または保持)する必要はありません。ブロックの宣言を含むスコープが破棄された後も、そのブロックを使用する可能性がある場合にのみ、ブロックのコピーを作成する必要があります。ブロックをコピーすると、ブロックはヒープに移動します。
ブロックプログラミングトピック.pdf (P.21)
MyAlertView を使用するとこうなる。
delegate は設定する必要がなくなったので nil としたが、もちろん必要なら設定する。
@implementation MyClass
- (void)showAlert
{
MyAlertView *alertView = [[MyAlertView alloc] initWithTitle:@"Title"
message:@"Message"
delegate:nil
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Other", nil];
[alertView showWithCompletionHandler:^(NSInteger buttonIndex) {
// Do something.
}];
[alertView autorelease];
}
@end
参考リンク
Blocks Programming Topic (iOS Developer Library)
ブロックプログラミングトピック.pdf (iOS Developer Library)