iOS URLNavigator库获取的topMost错误问题解决,父子控制器的addChild正确添加与移除步骤

2025.01.31 工作变动原因,故将一些工作期间Tapd内部写的Wiki文档转移到个人博客。

URLNavigator三方库 跳转失败,经过排查后发现获取的 UIViewcontroller.navigationController 为空的问题解决。

父子控制器的 addChild 正确添加与移除步骤。

一、问题排查过程

问题出现点源码


tapd_44062861_1714122687_959.png
    open func push(_ viewController: UIViewController, from: UINavigationControllerType? = nil, animated: Bool = true) -> UIViewController? {
        guard (viewController is UINavigationController) == false else { return nil }
        // 使用断点排查,发现在这里直接 { return nil }了,原因是获取UIViewController.topMost?.navigationController的时候,navigationController为空,所以决定对topMost方法进行排查。
        guard let navigationController = from ?? UIViewController.topMost?.navigationController else { return nil }
        guard self.delegate?.shouldPush(viewController: viewController, from: navigationController) != false else { return nil }
        navigationController.pushViewController(viewController, animated: animated)
        return viewController
      }

一路断点排查,发现在 navigationController 这里直接 { return nil }了,原因是获取 UIViewController.topMost?.navigationController 的时候,navigationController为空,所以决定对topMost方法进行排查

topMost方法

tapd_44062861_1714123000_598.png
        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
          if let childViewController = subview.next as? UIViewController {
          // 最终调试发现,三方库获取的childViewController并不是我正在显示的控制器,而是拿的subView第一个子控制器(第一个添加的子控制器视图),导致为空,所以要对子控制器进行添加、移除管理解决。
            return self.topMost(of: childViewController)
          }
        }

最终调试发现,三方库获取的 childViewController 并不是我正在显示的控制器,而是 拿的subView第一个子控制器(第一个添加的子控制器视图),导致为空。

因为我 只对子控制器做了添加(addChild),然后使用 subView.ishidden来控制隐藏出现的问题,所以要对子控制器进行添加、移除管理解决。

二、父子控制器的addChild添加、移除正确管理

主控制器mainVC

// 在主控制器点击 tab_A 切换子控制器
if title == "tab_A" {
    // 添加子控制器1
    let squareVC = UIViewController()
    // 将VC添加到控制器上,建立父子关系,这时可以通过`parentViewController`访问到父控制器;调用`addChildViewController`系统会自动调用`willMoveToParentViewController:` 
    addChild(squareVC)
    // 将VC控制器的view添加到父控制器上
    view.addSubview(squareVC.view)
    // 调用VC的`didMoveToParentViewController`通知VC完成了父子关系建立。
    squareVC.didMove(toParent: self)
    
    // 移除子控制器2
    let myVC = UIViewController()
    // 通知子控制器即将解除父子关系
    myVC.willMove(toParent: nil)
    // 将VC的view从父控制器移除
    myVC.view.removeFromSuperview()
    // 通过`removeFromParentViewController`真正解除父子关系,并且系统会调用`didMoveToParentViewController:`
    myVC.removeFromParent()
}
// 在主控制器点击 tab_B 切换子控制器
else if title == "tab_B" {
    // 添加子控制器2...
    
    // 移除子控制器1...
    
    // 原理同上
}

1. 子控制器添加:

  1. 将VC添加到控制器上,建立父子关系,这时可以通过 parentViewController 访问到父控制器;调用 addChildViewController 系统会自动调用 willMoveToParentViewController:
  2. 将VC控制器的view添加到父控制器上。
  3. 调用VC的 didMoveToParentViewController 通知VC完成了父子关系建立。

2. 子控制器移除:

  1. 通知子控制器即将解除父子关系。
  2. 将VC的view从父控制器移除。
  3. 通过 removeFromParentViewController 真正解除父子关系,并且系统会调用 didMoveToParentViewController:

最终修改后具体实现:

tapd_44062861_1714123000_599.png

最最最后,完结撒花

告辞.jpeg
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容