UIAlertController 不会立即显示
UIAlertController does not show immediately
Xcode版本:7.2.1,iOS版本:9.1+
我正在尝试在 iPad 上显示一条 UIAlertController 警报消息,该消息显示一条 "Loading...Please Wait" 消息,上面没有任何按钮。我在开始长时间操作之前显示 UIAlertController,然后在长时间操作之后,我关闭 UIAlertController。 然而,UIAlertController 并没有立即出现。它只会在较长的操作完成后短暂闪烁,然后消失。
一般代码结构如下:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
/// Perform long operation here...
/// (Basically, a message is being sent to a server, a long operation happens on
/// the server, and then the server returns a response to the iPad client.)
[alert dismissViewControllerAnimated:YES completion:nil];
}
我尝试了很多替代方法,比如使用 dispatch_async 以便在长时间操作发生时可以同时显示警报消息:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/// Perform long operation here...
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
});
}
我试过使用 UIAlertView(我知道它在 iOS 8 中被弃用),无论是单独使用还是与 dispatch 一起使用,但这也不起作用。
我试过将长操作代码包装在 performSelector 消息中,但无济于事。
过去,使用带有 dispatch_queue 的 UIAlertView 可以无缝地应对这种情况。
感谢任何帮助。
编辑:
一件有趣的事情需要注意:在 dispatch_async 代码中,如果我在调用长操作代码之前添加一个 usleep(250000),大约 80% 的时间,UIAlertController 警报消息将被显示在正确的时间:在长时间操作开始之前。但是,这不是 100% 的时间,也不是可持续的解决方案。使用较小的数字调用 usleep 无效。
请注意,对于 DISPATCH_QUEUE_PRIORITY_DEFAULT 选项,我还尝试了:
DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_LOW 和 DISPATCH_QUEUE_PRIORITY_BACKGROUND
而且,我也尝试了以下方法:
dispatch_queue_t myQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myQueue, ^{
/// Perform long operation here...
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
});
尝试在显示警报控制器时将 CFRunLoopWakeUp(CFRunLoopGetCurrent()) 放在下方。
最终起作用的是调度代码和 CFRunLoopWakeUp 调用的组合(@Bhavuk Jain 建议)。我还必须做的是将最初在调度块之后的代码(我没有在原始 post 中显示)移动到调度块内部。因此,到目前为止,以下工作正常:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Initialize and present the alert view controller.
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
// Force wake up the run loop.
CFRunLoopWakeUp(CFRunLoopGetCurrent());
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/// Perform long operation here...
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
/// Execute rest of code INDSIDE the dispatch code block INSTEAD of after it...
});
});
}
在最初的 post 我标记为答案(5 月 31 日)时,在某些情况下 AlertViewController 消息会挂起,因为不会调用 dismissViewController 方法。 (也许各种线程中的一些竞争条件......我不确定。)所以我最终发现可靠地工作并且似乎是更清洁的解决方案是使用 AlertViewController 的完成块和 dispatch_after 的组合打电话。
更多关于来自 iOS reference 的完成调用:"The completion handler gets called after the viewDidAppear: method is called on the presented view controller."
(This post 有帮助。)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Initialize the alert view controller.
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
// Present the alert view controller.
[self presentViewController:alert animated:YES completion:^{
/// Perform long operation here...
dispatch_after(0, dispatch_get_main_queue(), ^{
// Dismiss the alert message.
[loadAlertController dismissViewControllerAnimated:YES completion:nil];
/// Execute rest of code INDSIDE the dispatch code block INSTEAD of after it...
});
}];
}
Xcode版本:7.2.1,iOS版本:9.1+
我正在尝试在 iPad 上显示一条 UIAlertController 警报消息,该消息显示一条 "Loading...Please Wait" 消息,上面没有任何按钮。我在开始长时间操作之前显示 UIAlertController,然后在长时间操作之后,我关闭 UIAlertController。 然而,UIAlertController 并没有立即出现。它只会在较长的操作完成后短暂闪烁,然后消失。
一般代码结构如下:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
/// Perform long operation here...
/// (Basically, a message is being sent to a server, a long operation happens on
/// the server, and then the server returns a response to the iPad client.)
[alert dismissViewControllerAnimated:YES completion:nil];
}
我尝试了很多替代方法,比如使用 dispatch_async 以便在长时间操作发生时可以同时显示警报消息:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/// Perform long operation here...
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
});
}
我试过使用 UIAlertView(我知道它在 iOS 8 中被弃用),无论是单独使用还是与 dispatch 一起使用,但这也不起作用。
我试过将长操作代码包装在 performSelector 消息中,但无济于事。
过去,使用带有 dispatch_queue 的 UIAlertView 可以无缝地应对这种情况。
感谢任何帮助。
编辑:
一件有趣的事情需要注意:在 dispatch_async 代码中,如果我在调用长操作代码之前添加一个 usleep(250000),大约 80% 的时间,UIAlertController 警报消息将被显示在正确的时间:在长时间操作开始之前。但是,这不是 100% 的时间,也不是可持续的解决方案。使用较小的数字调用 usleep 无效。
请注意,对于 DISPATCH_QUEUE_PRIORITY_DEFAULT 选项,我还尝试了: DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_LOW 和 DISPATCH_QUEUE_PRIORITY_BACKGROUND
而且,我也尝试了以下方法:
dispatch_queue_t myQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myQueue, ^{
/// Perform long operation here...
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
});
尝试在显示警报控制器时将 CFRunLoopWakeUp(CFRunLoopGetCurrent()) 放在下方。
最终起作用的是调度代码和 CFRunLoopWakeUp 调用的组合(@Bhavuk Jain 建议)。我还必须做的是将最初在调度块之后的代码(我没有在原始 post 中显示)移动到调度块内部。因此,到目前为止,以下工作正常:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Initialize and present the alert view controller.
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
// Force wake up the run loop.
CFRunLoopWakeUp(CFRunLoopGetCurrent());
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/// Perform long operation here...
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
/// Execute rest of code INDSIDE the dispatch code block INSTEAD of after it...
});
});
}
在最初的 post 我标记为答案(5 月 31 日)时,在某些情况下 AlertViewController 消息会挂起,因为不会调用 dismissViewController 方法。 (也许各种线程中的一些竞争条件......我不确定。)所以我最终发现可靠地工作并且似乎是更清洁的解决方案是使用 AlertViewController 的完成块和 dispatch_after 的组合打电话。
更多关于来自 iOS reference 的完成调用:"The completion handler gets called after the viewDidAppear: method is called on the presented view controller."
(This post 有帮助。)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Initialize the alert view controller.
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
// Present the alert view controller.
[self presentViewController:alert animated:YES completion:^{
/// Perform long operation here...
dispatch_after(0, dispatch_get_main_queue(), ^{
// Dismiss the alert message.
[loadAlertController dismissViewControllerAnimated:YES completion:nil];
/// Execute rest of code INDSIDE the dispatch code block INSTEAD of after it...
});
}];
}