暂停代码执行,直到按下UIAlertViewbutton?
我的一个方法发送消息给一个对象(你知道些什么),并期望一个BOOL答案。 但是,BOOL回答它所期望的是基于在接收对象的方法中创build的UIAlertView的答案。 但是,等待用户回答UIAlertView时,代码不会暂停。 我的问题是:如何在方法的返回值中使用-alertView:clickedButtonAtIndex?
这里是消息运行的代码(在这个构造中,我期望navigateAwayFromTab根据UIAlertView中的用户input进行更改,但是它永远不会有机会):
- (BOOL)readyToNavigateAwayFromTab { NSLog( @"message received by Medical View"); navigateAwayFromTab = NO; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Navigate Away From Tab?" message:@"Navigating away from this tab will save your work." delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil ]; [alert show]; [alert release]; return navigateAwayFromTab; } #define CANCEL 0 #define OK 1 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if( buttonIndex == OK ) navigateAwayFromTab = YES; }
我一直在阅读关于模态UIAlertView的辩论,并且我同意苹果的实施 – 至less作为规则。 然而,在这种情况下,我没有看到通过在-alertView:clickedButtonAtIndex解决问题的任何方式,因为我不需要运行基于UIAlertView的代码,我只需要读取响应。 关于如何能够达到我的监禁的任何build议? 我已经尝试了[alert show]之后的一个while循环,但是之后警报甚至没有显示,出于多种原因我不能使用-viewWillDisapear。
编辑
对于那些在现代ios时代看这个问题的人来说,这个问题涉及到ios 2
不仅UIAlertView的显示不等待用户触摸button,甚至不等待警报视图淡入视图。 它立即返回。
给你的class级添加一个标志。 如果是NO,请从readyToNavigateAwayFromTab返回NO并显示您的警报。 在clickedButtonAtIndex中,设置标志以便readyToNavigateAwayFromTab知道返回YES。 仍然在clickedButtonAtIndex中,重试代码中的标签导航。
从后台线程触发时使用NSCondition的解决scheme:
// on background thread condition = [NSCondition new]; questionAnswered = NO; // display UIAlertView in a method on main thread with -performSelectorOnMainThread:withObject:waitUntilDone: [condition lock]; while (! questionAnswered) [condition wait]; questionAnswered = NO; [condition unlock]; [condition release]; // on main thread in delegate method -alertView:clickedButtonAtIndex: // (do something with choosen buttonIndex) questionAnswered = YES; [condition signal]; [condition unlock]
拉斐尔
[alert show]
语句应该保留应用程序,直到提供响应。
你有没有让你的控制器订阅UIAlertViewDelegate
协议? 检查是否需要将<UIAlertViewDelegate>
添加到控制器头文件中,例如:
@interface RootViewController : UIViewController <UIAlertViewDelegate, UITabBarDelegate, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
您也可以使navigateAwayFromTab
variables属性,例如:
@interface RootViewController : UIViewController <UIAlertViewDelegate> { BOOL navigateAwayFromTab; } @property BOOL navigateAwayFromTab; ... @end
在执行中:
@implementation RootViewController @synthesize navigateAwayFromTab; ... - (void) readyToNavigateAwayFromTab { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Navigate Away From Tab?" message:@"Navigating away from this tab will save your work." delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil ]; [alert show]; [alert release]; } #define CANCEL 0 #define OK 1 - (void) alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if ([actionSheet.title compare:@"Navigate Away From Tab?"] == NSOrderedSame) { if (buttonIndex == OK) self.navigateAwayFromTab = YES; else self.navigateAwayFromTab = NO; } }
我发现最好的解决scheme是来自Sasmito Adibowo在他的博客文章Painless UIAlertView 。 他创build了BSAlertViewDelegateBlock,一个通用的UIAlertViewDelegate实现,允许您使用闭包作为委托处理程序。
以下是你如何使用它:
UIAlertView* alert = ...; BSAlertViewDelegateBlock* alertDelegate = [[BSAlertViewDelegateBlock alloc] initWithAlertView:alert]; alertDelegate.didDismissWithButtonIndexBlock = ^(UIAlertView* alertView, NSInteger buttonIndex) { switch (buttonIndex) { ... } }; [alert show];
BSAlertViewDelegateBlock.h和BSAlertViewDelegateBlock.m的实现在GitHub上可用,但是我在这里重新发布了代码:
BSAlertViewDelegateBlock.h
#import <UIKit/UIKit.h> /** Adapts UIAlertViewDelegate protocol into a block-friendly interface. */ @interface BSAlertViewDelegateBlock : NSObject<UIAlertViewDelegate> /** Designated initializer. */ -(id) initWithAlertView:(UIAlertView*) alertView; @property (nonatomic,strong) void(^clickedButtonAtIndexBlock)(UIAlertView* alertView,NSInteger buttonIndex); @property (nonatomic,strong) void(^alertViewCancelBlock)(UIAlertView* alertView); @property (nonatomic,strong) void(^willPresentAlertViewBlock)(UIAlertView* alertView); @property (nonatomic,strong) void(^didPresentAlertViewBlock)(UIAlertView* alertView); @property (nonatomic,strong) void(^willDismissWithButtonIndexBlock)(UIAlertView* alertView,NSInteger buttonIndex); @property (nonatomic,strong) void(^didDismissWithButtonIndexBlock)(UIAlertView* alertView,NSInteger buttonIndex); @property (nonatomic,strong) BOOL(^alertViewShouldEnableFirstOtherButtonBlock)(UIAlertView* alertView); @end
BSAlertViewDelegateBlock.m
#import <objc/runtime.h> #import "BSAlertViewDelegateBlock.h" const char* const BSAlertViewDelegateBlockKey = "BSAlertViewDelegateBlockKey"; @interface BSAlertViewDelegateBlock () @property (nonatomic,weak) UIAlertView* alertView; @end @implementation BSAlertViewDelegateBlock -(void) alertViewDelegateBlock_cleanup { UIAlertView* alertView = self.alertView; // remove all handler blocks in case one of these blocks inadvertendly caused a circular reference to this delegate object. self.clickedButtonAtIndexBlock = nil; self.alertViewCancelBlock = nil; self.willPresentAlertViewBlock = nil; self.didPresentAlertViewBlock = nil; self.willDismissWithButtonIndexBlock = nil; self.didDismissWithButtonIndexBlock = nil; self.alertViewShouldEnableFirstOtherButtonBlock = nil; // finally remove this delegate from the alert view if (alertView.delegate == self) { alertView.delegate = nil; objc_setAssociatedObject(alertView, BSAlertViewDelegateBlockKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } -(id) initWithAlertView:(UIAlertView *)alertView { if (self = [super init]) { self.alertView = alertView; objc_setAssociatedObject(alertView, BSAlertViewDelegateBlockKey, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC); alertView.delegate = self; } return self; } #pragma mark UIAlertViewDelegate // Called when a button is clicked. The view will be automatically dismissed after this call returns - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { void(^clickedButtonAtIndexBlock)(UIAlertView* alertView,NSInteger buttonIndex) = self.clickedButtonAtIndexBlock; if (clickedButtonAtIndexBlock) { clickedButtonAtIndexBlock(alertView,buttonIndex); } } // Called when we cancel a view (eg. the user clicks the Home button). This is not called when the user clicks the cancel button. // If not defined in the delegate, we simulate a click in the cancel button - (void)alertViewCancel:(UIAlertView *)alertView { void(^alertViewCancelBlock)(UIAlertView* alertView) = self.alertViewCancelBlock; if (alertViewCancelBlock) { alertViewCancelBlock(alertView); } [self alertViewDelegateBlock_cleanup]; } - (void)willPresentAlertView:(UIAlertView *)alertView { void(^willPresentAlertViewBlock)(UIAlertView* alertView) = self.willPresentAlertViewBlock; if (willPresentAlertViewBlock) { willPresentAlertViewBlock(alertView); } } - (void)didPresentAlertView:(UIAlertView *)alertView { void(^didPresentAlertViewBlock)(UIAlertView* alertView) = self.didPresentAlertViewBlock; if (didPresentAlertViewBlock) { didPresentAlertViewBlock(alertView); } } - (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex { void(^willDismissWithButtonIndexBlock)(UIAlertView* alertView,NSInteger buttonIndex) = self.willDismissWithButtonIndexBlock; if (willDismissWithButtonIndexBlock) { willDismissWithButtonIndexBlock(alertView,buttonIndex); } } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { void(^didDismissWithButtonIndexBlock)(UIAlertView* alertView,NSInteger buttonIndex) = self.didDismissWithButtonIndexBlock; if (didDismissWithButtonIndexBlock) { didDismissWithButtonIndexBlock(alertView,buttonIndex); } [self alertViewDelegateBlock_cleanup]; } - (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView { BOOL(^alertViewShouldEnableFirstOtherButtonBlock)(UIAlertView* alertView) = self.alertViewShouldEnableFirstOtherButtonBlock; if (alertViewShouldEnableFirstOtherButtonBlock) { return alertViewShouldEnableFirstOtherButtonBlock(alertView); } // default to enable. return YES; } @end