0

I have a piece of code that, when a row in a table view is selected, will display an alert and wait until that alert is dismissed. 虽然它在装有 iOS 5 和 6 的 iPad 上运行良好,但在 iOS 7 上它在尝试解除警报时卡住了。

为了说明这个问题,我创建了一个简单的主从应用程序并创建了一个简单的 MyAlert 类,它扩展了 UIAlertView 并符合 UIAlertViewDelegate:

@interface MyAlert : NSObject <UIAlertViewDelegate>
{
    volatile BOOL completed;
    UIAlertView * alert;
}

- (void) showAndWaitUntilDone:(NSString*)message;

@结尾

我的警报.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 卡在 iOS 7 上

如前所述,这在 iOS 5 和 6 上运行良好。

如果我不阻塞主线程,一切似乎都可以正常工作,但是,如果我从 UIButton 回调运行此代码,它就像一个魅力。

4

2 回答 2

4

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

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

于 2013-10-01T11:39:28.383 回答
2

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

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

于 2013-09-30T15:49:25.927 回答