之前在使用 presentViewController 去显示 UIAlertController 的时候遇到一个问题。
考虑下面这种情况,A 页面发起了一个异步的 HTTP 请求,在请求返回的时候,需要弹出一个 UIAlertController 来显示结果,理所当然,我会把下面这行代码写在 A 页面。
[self presentViewController:alertController animated:YES completion:nil];
但如果在返回结果之前,用户离开了 A 页面,这个时候就会报下面这个错了。
Attempt to present <UIAlertController: 0x1003e4870> on <TabViewController: 0x10034d9d0> whose view is not in the window hierarchy!
问题就出现在 self 这里,这里必须是当前的 ViewController 才行。所以要解决这个问题,就要找到你当前所在的 ViewController,然后在那里把 UIAlertController 显示出来。
后来我在网上找到了一段神奇的代码,写得真的太好了,简直就像魔法。无论你的入口是 UIViewController,还是 UINavigationController,又或者是 UITabBarController,都适用。
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:self.window.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
最后在 A 页面当中,这样改就行了。我这里是把上面的方法写在了 AppDelegate 当中。
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController *vc = [appDelegate topViewController];
[vc presentViewController:alertController animated:YES completion:nil];