我有一段代码,当选择表视图中的一行时,将显示一个警报并等待该警报被取消。虽然它在iOS 5和6的iPad上运行良好,但在iOS 7上它会在试图解除警报时卡住。
为了说明这个问题,我创建了一个简单的主从应用程序并创建了一个简单的MyAlert类,它扩展了UIAlertView并符合UIAlertViewDelegate:
@interface MyAlert : NSObject <UIAlertViewDelegate>
{
volatile BOOL completed;
UIAlertView * alert;
}
- (void) showAndWaitUntilDone:(NSString*)message;
@end
MyAlert.m:
@implementation MyAlert
- (void) showAndWaitUntilDone:(NSString*)message
{
alert = [[UIAlertView alloc] initWithTitle:@"Alert"
message:message
delegate:nil
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Other", nil];
if (alert)
{
alert.delegate = self;
[self showAndWaitUnitlDone];
}
}
- (void) showAndWaitUnitlDone
{
completed = NO;
[alert show];
while (!completed)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
}
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
completed = YES;
}
@end
然后我在我的ViewController中显示警告,如下所示:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[MyAlert showAndWaitUntilDone:@"test msg"];
}
效果:
如前所述,这适用于iOS 5和6。
如果我没有阻止主线程,那么一切似乎都运行正常,但是,如果我运行此代码,例如从UIButton回调它就像一个魅力。
答案 0 :(得分:4)
iOS 7中似乎存在一个错误,导致在RunLoop启动后永远不会调用UIAlertView委托。当等待UIAlertView的线程不是主线程时,它的行为完全相同。人们建议使用UIAlertView块或编写自定义警报视图。
有关详细信息,请参阅Apple的开发人员论坛主题:https://devforums.apple.com/message/887792
答案 1 :(得分:2)
也许只是我,但这首先看起来像是糟糕的设计。你将主线程锁定了一段未知的时间 为什么不简单地让didSelectRowAtIndexPath显示警报,并让警报回调(alertView:clickedButtonAtIndex :)执行您正在等待的剩余工作(或调用将执行此操作的函数)?如果需要,可以使用一个变量来存储哪个条目被点击...这样可以防止绑定主线程的负面影响,同时仍然给出看起来像你想要的效果。
如果apple实现了阻止应用程序设计者锁定主线程的东西(这就是为什么你的代码只有在waitUntilDone:设置为NO,基本上把代码放在异步调用上时)才会让我感到惊讶。