【问题标题】:UIWindow setRootViewController not clearing existing hierarchyUIWindow setRootViewController 不清除现有层次结构
【发布时间】:2015-01-03 22:11:55
【问题描述】:

在我的应用程序中,我以编程方式根据用户操作更改根视图控制器,例如登录/注销功能。

在 iOS 8 中 - 我注意到一个奇怪的问题。即使在窗口上设置了 rootViewController,旧的层次结构仍然存在。我只是通过捕获视图层次结构来验证它。

- (void) logout{
     [self.window setRootViewController:[self loadLoginView]];
}

-(UIViewController *) loadLoginView{
      WelcomeScreenVC *wsVC;
      wsVC = [[WelcomeScreenVC alloc] initWithNibName:@"WelcomeScreenVC" bundle:nil];
      UINavigationController *onboardingVC = [[UINavigationController alloc]initWithRootViewController:wsVC];
      return onboardingVC;
 }

即使在执行了这行代码之后,旧的登录视图层次结构仍然存在。如果有人能建议幕后发生的事情,将不胜感激。

编辑:我刚刚查看了 UIWindow setRootViewController 文档,以下是 Apple 对此的评价:

根视图控制器提供窗口的内容视图。 将视图控制器分配给此属性(以编程方式 或使用 Interface Builder)将视图控制器的视图安装为 窗口的内容视图。如果窗口具有现有视图 层次结构,旧视图在新视图被删除之前被删除 已安装。

【问题讨论】:

  • 可以分享[self loadLoginView]的代码吗?
  • @JoshHeald 将其添加到问题中
  • 是直接从您的应用中复制出来的,还是您输入的?我问是因为 loadLoginView 声明了 void 返回类型,这无济于事
  • @JoshHeald,对不起,我从应用程序中复制了它,但在编辑时删除了一些敏感信息。该方法的返回类型是 UIViewController
  • 没问题。我正在努力重新创建它,但想知道你是如何检查层次结构的——你说你“通过捕获视图层次结构来验证它”,这是使用新的 Xcode 6 View Hierarchy Debugger 还是其他方式?跨度>

标签: ios uiview ios8 uikit


【解决方案1】:

我注意到了同样的事情。

基本上,我有一个相当复杂的故事板,用作登录/欢迎界面。这个界面位于一个导航控制器中,它以模态方式呈现另一个导航控制器。

在某个时间点之后,用户采取了一项将他转换到主界面的操作。使用 iOS 8 视图调试器,我注意到在设置窗口的 rootViewController 属性后,旧的视图层次结构仍然存在。

我的解决方案,现在是在我重新评估 window.rootViewController 属性之前使用以下代码:

for (UIView* subView in self.window.rootViewController.view.subviews) {
    [subView removeFromSuperview];
}
[self.window.rootViewController.view removeFromSuperview];

它并不漂亮,但它确实有效。

我注意到的另一件奇怪的事情是欢迎界面的模态呈现的 viewController 没有使用此方法正确清理。我必须手动关闭它并进行清理。

【讨论】:

  • 这似乎在显示的 UI 方面有效,但由于某种原因,正确的屏幕现在没有启用交互......所以我无法点击任何按钮或文本字段......任何想法?我之前遇到过类似的问题,没有显示正确的 UI,并且以前的 UI 变得有些无响应,因此标签栏项目会显示它们已被选中,但不会执行任何更改。
  • 为我的情况找到了一个替代解决方案,在执行一组冗长的网络连接时交换根视图控制器我最终会留下旧的 UI(如果我足够快的话) , 按钮功能但标签栏按钮不会改变标签控制器的视图。 CGRect windowFrame = self.window.frame; self.window.rootViewController = nil; self.window = nil; UIWindow* newWindow = [[UIWindow alloc] initWithFrame: windowFrame]; [新窗口 makeKeyAndVisible]; self.window = newWindow;
【解决方案2】:
var loginNavigationController: OnBoardViewController?{
    willSet{
        if newValue == nil {
            loginNavigationController?.view.removeFromSuperview()
        }
    }
}

loginNavigationController = nil 然后设置window.rootviewcontroller = {不同的VC}

【讨论】:

    【解决方案3】:

    最好的修复方法是:

    self.window.subviews.forEach { $0.removeFromSuperview() }
    

    或者,旧式:

    for view in self.window.subviews {
       view.removeFromSuperview()
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-11
      • 2019-02-17
      • 2019-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多