暂停代码执行,直到按下UIAlertView按钮?

时间:2009-09-03 19:17:56

标签: iphone ios

我的一个方法向对象发送一条消息(你对此有何了解),并希望得到一个BOOL答案。但是,BOOL回答它的期望是基于在接收对象的方法中创建的UIAlertView的答案。但是,代码在等待用户回答UIAlertView时不会暂停。我的问题是:如何在方法的返回值中使用-alertView:clickedButtonAtIndex?

这是消息运行的代码(在这种结构中,我期望navigationAwayFromTab根据UIAlertView中的用户输入进行更改,但它永远不会有机会):

- (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辩论,我同意苹果的实施 - 至少作为规则。但是,在这种情况下,我没有看到通过将代码放在-alertView:clickedButtonAtIndex中解决问题的任何方法,因为我不需要运行基于UIAlertView的代码,我只需要阅读响应。关于如何达到我的监狱的任何建议?我已经在[alert show]之后尝试了一段时间循环,但随后警报甚至没有显示,并且出于多种原因我不能使用-viewWillDisapear。

修改

对于那些在现代ios时代观看这个问题的人来说,这个问题与ios 2有关。

4 个答案:

答案 0 :(得分:10)

UIAlertView的节目不仅没有等待用户触摸按钮,它甚至不等待警报视图淡入视图。它立即返回

为您的班级添加一个标志。如果为NO,则从readyToNavigateAwayFromTab返回NO并显示您的警报。在clickedButtonAtIndex中,设置标志,以便readyToNavigateAwayFromTab知道返回YES。仍然在clickedButtonAtIndex中,从代码重试标签导航。

答案 1 :(得分:4)

从后台线程触发时使用NSCondition的解决方案:

// 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]

圣拉斐尔

答案 2 :(得分:1)

我找到的最佳解决方案来自Sasmito Adibowo在他的博文Painless UIAlertView中。他创建了BSAlertViewDelegateBlock,这是一个通用的UIAlertViewDelegate实现,允许您将闭包用作委托处理程序。

以下是您如何使用它:

UIAlertView* alert = ...;
BSAlertViewDelegateBlock* alertDelegate = [[BSAlertViewDelegateBlock alloc] initWithAlertView:alert];
alertDelegate.didDismissWithButtonIndexBlock = ^(UIAlertView* alertView, NSInteger buttonIndex)
{
    switch (buttonIndex)
    {
        ...
    }
};
[alert show];

GitHub上提供了BSAlertViewDelegateBlock.hBSAlertViewDelegateBlock.m的实现,但我已在此处重新发布了代码:

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

答案 3 :(得分:0)

[alert show]语句应该暂停应用程序,直到提供响应为止。

您是否让控制器订阅了UIAlertViewDelegate协议?检查是否需要将<UIAlertViewDelegate>添加到控制器头文件中,例如:

@interface RootViewController : UIViewController <UIAlertViewDelegate, UITabBarDelegate, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>

您也可以将navigateAwayFromTab变量设为属性,例如:

@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;
   }
}