UI在iOS 7上被卡住,同时解除了iPad上didSelectRowAtIndexPath显示的警报

时间:2013-09-30 14:49:44

标签: ios ipad uitableview uialertview

我有一段代码,当选择表视图中的一行时,将显示一个警报并等待该警报被取消。虽然它在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"];
}

效果: UIAlertView stuck on iOS 7

如前所述,这适用于iOS 5和6。

如果我没有阻止主线程,那么一切似乎都运行正常,但是,如果我运行此代码,例如从UIButton回调它就像一个魅力。

2 个答案:

答案 0 :(得分:4)

iOS 7中似乎存在一个错误,导致在RunLoop启动后永远不会调用UIAlertView委托。当等待UIAlertView的线程不是主线程时,它的行为完全相同。人们建议使用UIAlertView块或编写自定义警报视图。

有关详细信息,请参阅Apple的开发人员论坛主题:https://devforums.apple.com/message/887792

答案 1 :(得分:2)

也许只是我,但这首先看起来像是糟糕的设计。你将主线程锁定了一段未知的时间 为什么不简单地让didSelectRowAtIndexPath显示警报,并让警报回调(alertView:clickedButtonAtIndex :)执行您正在等待的剩余工作(或调用将执行此操作的函数)?如果需要,可以使用一个变量来存储哪个条目被点击...这样可以防止绑定主线程的负面影响,同时仍然给出看起来像你想要的效果。

如果apple实现了阻止应用程序设计者锁定主线程的东西(这就是为什么你的代码只有在waitUntilDone:设置为NO,基本上把代码放在异步调用上时)才会让我感到惊讶。