提问人:valeriana 提问时间:1/30/2021 更新时间:2/3/2021 访问量:59
(目标-C)通过 window.rootView 和 keyWindow 访问导航堆栈的区别
(Objective-C) Difference between accessing the navigation stack through the window.rootView and keyWindow
问:
有谁知道两者之间有什么区别
TabBarController* tabBar = (TabBarController *)_window.rootViewController;
UINavigationController* navigationController = tabBar.selectedViewController;
ViewController* initialViewController = (ViewController *)navigationController.topViewController;
和这个
UINavigationController* navigationController = [UIApplication sharedApplication].keyWindow.rootViewController.navigationController;
ViewController* initialViewController = (ViewController *)navigationController.topViewController;
我的假设:
在示例 A 中,我使用的是特定的导航堆栈(不能依赖该堆栈,因为我正在尝试在通用链接后返回应用程序时处理呈现 VC,并且它并不总是可用)。
在示例 B 中,我正在尝试访问我当前所在的导航堆栈。
这两个示例的最后一行,我试图将新的 VC 推到堆栈的顶部。
我的结果:
- 示例 A 成功地将我的新 VC 推送到堆栈上,而示例 B 则没有。
撇开设计原则不谈(示例 B 现在看起来很笨拙,但到目前为止我所拥有的只是这些),我真的不明白这两个示例的区别,它们的性能不应该一样吗?谁能说明为什么这些不同?
答:
UIViewController 上的 navigationController 属性可为 null,因此它可能返回 nil。
UINavigationController 上的 topViewController 属性也可为 null,并返回 UIViewController?,而不是特定类。简单地将任何 UIViewController 强制转换为 ViewController 是不安全的,因此应针对 isKindOfClass 进行检查。
同样的事情也适用于 rootViewController,它可能并不总是 TabBarController,因此无条件地强制转换它是不安全的。
- 此外,还发现如果 rootViewController 的类型为 UITableViewController,则 navigationController 为 nil。
navigationController 方法将返回一个父视图控制器,即最接近的父 UINavigationController。在您的示例中,它看起来好像根视图控制器是 UITabBarController,每个选项卡中都有一个 UINavigationController。在选项卡控制器上调用 -navigationController 将返回 nil,因为它没有父视图控制器(实际上,它是根)。
如果应用程序中有多个窗口,则 -keyWindow 可以更改。这种方法在 iOS 13 中也被弃用,因为现在可以有多个窗口场景,所以如果你知道你所处的特定窗口,最好使用它,而不是从 UIApplication 开始并向下钻取。
编辑:如果目标是呈现一个新的视图控制器,您将从根视图控制器开始,然后沿着呈现的视图控制器走,并在其上呈现您的新视图控制器。
@implementation UIViewController (MyOvertop)
- (void)my_presentOvertopViewController:(UIViewController *)other animated:(BOOL)animated completion:(void (^ _Nullable)(void))completion
{
UIViewController *topmost = self;
while (topmost.presentedViewController &&
![topmost.presentedViewController isBeingDismissed])
{
topmost = topmost.presentedViewController;
}
if (topmost.transitionCoordinator) {
// transition already going on, wait til it's done and try again
[topmost.transitionCoordinator animateAlongsideTransition:nil completion:^(id context) {
dispatch_async(dispatch_get_main_queue(), ^{
[self my_presentOvertopViewController:vc animated:animated completion:completion];
});
}];
return;
}
if (topmost != other) {
[topmost presentViewController:other animated:animated completion:completion];
}
}
@end
(上面可能有错别字,但这就是这个想法)
评论