UIAlertViewでとまどったこと…その2
先日の日記「UIAlertViewでとまどったこと…その1」では、アラート表示中にホームボタンを押すと困ったことになるかもしれない…ということを書きました。で、iPhoneにはもう1つボタンがありますよね?
そう、電源ボタンです。
この電源ボタンがUIAlertViewに更なる悲劇をおよぼすことに…。
悲劇のメソッドdidDismissWithButtonIndex
UIAlertViewには様々なメソッドがありますが、先日紹介したのはこちら。
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
これはアラートのボタンを押すと呼ばれるメソッドですが、次のようなメソッドもあります。
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
これは、アラートのボタンを押してアラートが閉じた後に呼ばれるメソッドです。
私は「Touch Touch Shapes」でゲームオーバー後の選択を行う際に、このdidDismissWithButtonIndexを使用しました。
例えば「ゲームオーバー」→「コンティニュー」の動作の場合、clickedButtonAtIndexを使用するとアラートのウィンドウが消える前にゲームが再開されてしまうんですね。
ですがdidDismissWithButtonIndexを使用すると、アラートのウィンドウが消えてからゲームが再開されるので、処理的にも見た目的にも都合がよかった訳です。
が、しかし…
何故呼ぶ
「Touch Touch Shapes」のテスト中に、私はとある動作を行いました。それがアラート表示中に電源ボタンを押すことです。*1
ゲームオーバー中にその動作を行いスリープモードにし、続いてスリープを解除したところ…
あれ?アラートのボタンを押していないのにコンティニューされた?
しかもアラートが閉じられていない?
という謎の動作が!
ここで…サンプルコードを書いてみます。これも前回同様UIViewを継承したクラスに実装します。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AlertTest" message:@"Test" delegate:self cancelButtonTitle:@"Button1" otherButtonTitles:@"Button2", @"Button3", nil]; [alert show]; [alert release]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { NSLog(@"clickedButtonAtIndex"); NSLog(@"buttonIndex:%d", buttonIndex); } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { NSLog(@"didDismissWithButtonIndex"); NSLog(@"buttonIndex:%d", buttonIndex); }
そして、アラートを表示して電源ボタンを押すとデバッガコンソール上には…
didDismissWithButtonIndex
buttonIndex:0
それだけならまだしも、アラートが消えていない…。ここで試しに、アラートのButton2を押すとアラートが閉じ、デバッガコンソール上には…
clickedButtonAtIndex buttonIndex:1 didDismissWithButtonIndex buttonIndex:1
まとめるとこのような動作になります。
- アラートを表示する
- 電源ボタンを押してスリープモードにする
- そのときdidDismissWithButtonIndexが呼び出される
- スリープモードを解除
- アラートは閉じられていない
- アラートが開いている限り、電源ボタンを押すと何回でもdidDismissWithButtonIndexが呼び出される
解決方法
今回の場合は「アラートにキャンセルボタンを設定しない」「alertViewCancelを実装する」という方法では解決されませんでした。
そこで、私がとった方法は以下のようなフラグ処理です。
- 何か初期化処理のメソッド { pushFlag = false; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { pushFlag = true; NSLog(@"clickedButtonAtIndex"); NSLog(@"buttonIndex:%d", buttonIndex); } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { if (pushFlag) { NSLog(@"didDismissWithButtonIndex"); NSLog(@"buttonIndex:%d", buttonIndex); pushFlag = false; } }
グローバル変数のpushFlagを設定して、アラートのボタンが押された時だけdidDismissWithButtonIndex内の処理を実行するようにしています。
このdidDismissWithButtonIndexに関する動作…かなり凶悪なのでiPhoneアプリ開発者の皆さんには本当に知っていてほしいです。
「Touch Touch Shapes」制作時はOS2.2で動作確認を行いましたが、この動作はOS3.0でも変わっていませんでした。
「UIAlertViewでとまどったこと…その3」は今の所ありません。