按顺序显示 UIAlertViews
Posted
技术标签:
【中文标题】按顺序显示 UIAlertViews【英文标题】:Displaying UIAlertViews Sequentially 【发布时间】:2011-05-18 13:43:28 【问题描述】:我有几个 UIAlertViews 我想按顺序显示,并且只有在前一个 UIAlertView 被关闭后才继续显示下一个 UIAlertView(通过用户单击确定)。
我知道 didDismissWithButtonIndex 委托和添加标签,但这并没有太大帮助,因为可能会调用多达 3 个 UIAlertViews,并且不一定每次都以相同的顺序。见代码:
if(condition 1)
alert1 = // UIAlertView[[.....
[alert1 show]
if(condition 2)
alert2 = // UIAlertView[[.....
[alert2 show]
if(condition 3)
alert3 = // UIAlertView[[.....
[alert3 show]
上面只会添加 3 个警报(取决于满足多少条件),这不是我想要的。我希望一次只显示一个,然后在用户点击确定按钮后显示下一个(如果有的话)。
我的想法可能是将消息添加到队列中,然后处理该队列以在每次解除警报时删除警报,但我不确定 id 是如何做到这一点的。
任何想法将不胜感激。 谢谢
【问题讨论】:
【参考方案1】:您可以在 UIAlertView 委托方法中轻松完成此操作,该方法会在警报视图关闭后调用。所以,UIAlertViewDelegate 定义了如下委托方法:
– alertView:didDismissWithButtonIndex:
实现该方法,并确保您的类是您创建的 UIAlertViews 的委托。此方法是根据用户关闭的警报显示 next 警报的理想场所。
如果您的要求是“按顺序显示最多三个警报,但不总是以相同的顺序显示”我可能会将警报放入数组中,然后在委托方法中从数组中获取下一个警报显示。它实际上不必比这更复杂。关键是委托方法实现是显示下一个警报的最佳位置。
伪代码示例:
定义一个数组; NSMutableArray * alerts_;
- (void)showAlertSequence
if ( !alerts_ )
alerts_ = [[NSMutableArray alloc] init];
[alerts_ addObjects;<My alerts>];
[self showSequencedAlertFrom:nil];
- (BOOL)showSequencedAlertFrom:(UIAlertView *)sourceAlertView
if ( !sourceAlertView )
[[alerts_ objectAtIndex:0] show];
else
NSInteger index = [alerts_ indexOfObject:sourceAlertView];
if ( index < [alerts_ count] )
[[alerts_ objectAtIndex:index++] show];
return NO;
– alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)index
// Show the next alert or clean up if we're at the end of the sequence.
if ( ![self showSequencedAlertFrom:alertView] )
[alerts_ removeAllObjects];
顺便说一句;三个连续的警报真的会惹恼你的用户;)
【讨论】:
谢谢@dannywartnaby 这类似于我已经尝试过的东西。问题是在这里你假设所有的 alertViews 都存在。如果只存在 alertView 1 和 3 怎么办?如果是这种情况,您的伪代码将跳过 alert3。还是我遗漏了一些明显的东西? 这种方法的另一个问题是警报 1 不会总是存在,这意味着其他警报都不会显示。这就是为什么我正在考虑对委托方法使用不同的方法。感谢您的回复 好的,我明白了。好吧,我已经稍微更新了我的答案;底线是委托方法是,IMO,决定何时显示下一个警报的最佳位置。如果您不能始终如一地知道正在显示哪些警报以及以什么顺序显示,那么 IMO 将您要显示的警报放入一个集合中,然后在委托方法中迭代该集合,获得“下一个”是有意义的基于当前。 再次感谢!这似乎更符合逻辑。我试图实现这一点,但是当我关闭第一个 alertView 时,控制台返回:wait_fences: failed to receive reply: 10004003 message。应用程序停止。我看不出有什么明显的原因可能导致这种情况。再次感谢您的帮助,我想我快到了!【参考方案2】:我做过的一件事是通过在 AlertView 上添加类别来使用基于块的 UIAlertViews。
这是.h文件
@interface UIAlertView (WithBlocks)
- (id) initWithTitle:(NSString *)title message:(NSString *)message;
- (void) addButtonWithTitle:(NSString *)title andBlock:(void(^)())block;
@end
这是.m文件
static NSString *BUTTON_BLOCK_KEY = @"alertview-button-blocks";
@interface UIAlertView()
- (void) runBlock: (void (^)())block;
@end
@implementation UIAlertView (WithBlocks)
/**
* Initialized an alert view with a title and message.
*/
- (id) initWithTitle:(NSString *)title message:(NSString *)message
self = [self initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
if (self)
self.delegate = self;
NSMutableArray *buttonBlocks = [NSMutableArray array];
objc_setAssociatedObject(self, BUTTON_BLOCK_KEY, buttonBlocks, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return self;
/**
* Adds a button with a title and a block to be executed when that button is tapped.
*/
- (void) addButtonWithTitle:(NSString *)title andBlock:(void (^)())block
// Add the button
[self addButtonWithTitle:title];
NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
if (!block)
block = ^ /* empty block */ ;
[buttonBlocks addObject:[[[block copy] retain] autorelease]];
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
void (^block)() = (void (^)()) [buttonBlocks objectAtIndex:buttonIndex];
// Due to a timing issue, the current window is still the UIAlertView for a very
// short amount of time after it has been dismissed which messes up anything
// trying to get the current window in the blocks being run.
// Ergo, the block is being delayed by a tiny bit. (Amount determined through limited testing)
[self performSelector:@selector(runBlock:) withObject:block afterDelay:0.25];
- (void) runBlock: (void (^)())block
block();
@end
然后你可以通过下面的代码调用链式的alertviews
void(^continueBlock)(void) = ^
// Display more alertviews here
;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"message"];
[alert addButtonWithTitle:@"Continue" andBlock:continueBlock];
[alert addButtonWithTitle:@"Dismiss" andBlock:^
// Display more alertviews here
[alert show];
[alert release];
【讨论】:
【参考方案3】:我也在寻找解决这个问题的方法。这是我最终为自己的应用解决它的方式:
static BOOL alertShowing = FALSE;
UIAlertView *alert0 = [[UIAlertView alloc] initWithTitle:@"AlertView 0" message:@"This is the first alert" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Yes",@"No", nil];
[alert0 setTag:0];
alertShowing = TRUE;
[alert0 show];
while (alertShowing)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:@"AlertView 1" message:@"This is the second alert" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Yes",@"No", nil];
[alert1 setTag:1];
alertShowing = TRUE;
[alert1 show];
while (alertShowing)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
// add some more alerts here for dramatic effect ...
您的按钮处理程序必须在每个退出路径中设置alertShowing = FALSE'
。
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
// Deal with handling responses for your different alerts here.
switch ([alertView tag])
case 0:
// handler first alert here
break;
case 1:
// handler second alert here
break;
default:
// etc.
break;
alertShowing = FALSE;
可能有比创建一个新的运行循环更好的坐下来旋转的方法,并且有一些重复的代码可能可以更好地通用化。从好的方面来说,它很简单,不需要一堆排队逻辑。我为这种模式使用了#define 来避免手动输入它,并且在我的情况下它运行良好。
【讨论】:
【参考方案4】:这就是我按照您的建议使用警报队列的方法。
@property (strong, nonatomic) NSMutableArray *alertQueue;
@property (nonatomic) BOOL showingAlert;
- (void)showAlert:(UIAlertView *)alert
if (self.showingAlert)
[self.alertQueue addObject:alert];
else
self.showingAlert = YES;
[alert show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
if ([self.alertQueue count])
UIAlertView *alert = [self.alertQueue objectAtIndex:0];
[self.alertQueue removeObjectAtIndex:0];
[alert show];
else self.showingAlert = NO;
然后,每当您想显示警报时,您只需创建 UIAlertView 并将其传递给 showAlert 方法,它只会在所有早期警报都被解除后才会显示。
【讨论】:
以上是关于按顺序显示 UIAlertViews的主要内容,如果未能解决你的问题,请参考以下文章