2025.01.31 工作變動(dòng)原因,故將一些工作期間Tapd內(nèi)部寫的Wiki文檔轉(zhuǎn)移到個(gè)人博客。
URLNavigator三方庫(kù)跳轉(zhuǎn)失敗,經(jīng)過(guò)排查后發(fā)現(xiàn)獲取的UIViewcontroller.navigationController為空的問(wèn)題解決。父子控制器的
addChild正確添加與移除步驟。
一、問(wèn)題排查過(guò)程
問(wèn)題出現(xiàn)點(diǎn)源碼

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 }
// 使用斷點(diǎn)排查,發(fā)現(xiàn)在這里直接 { return nil }了,原因是獲取UIViewController.topMost?.navigationController的時(shí)候,navigationController為空,所以決定對(duì)topMost方法進(jìn)行排查。
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
}
一路斷點(diǎn)排查,發(fā)現(xiàn)在 navigationController 這里直接 { return nil }了,原因是獲取 UIViewController.topMost?.navigationController 的時(shí)候,navigationController為空,所以決定對(duì)topMost方法進(jìn)行排查。
topMost方法

tapd_44062861_1714123000_598.png
// child view controller
for subview in viewController?.view?.subviews ?? [] {
if let childViewController = subview.next as? UIViewController {
// 最終調(diào)試發(fā)現(xiàn),三方庫(kù)獲取的childViewController并不是我正在顯示的控制器,而是拿的subView第一個(gè)子控制器(第一個(gè)添加的子控制器視圖),導(dǎo)致為空,所以要對(duì)子控制器進(jìn)行添加、移除管理解決。
return self.topMost(of: childViewController)
}
}
最終調(diào)試發(fā)現(xiàn),三方庫(kù)獲取的 childViewController 并不是我正在顯示的控制器,而是 拿的subView第一個(gè)子控制器(第一個(gè)添加的子控制器視圖),導(dǎo)致為空。
因?yàn)槲?只對(duì)子控制器做了添加(addChild),然后使用 subView.ishidden來(lái)控制隱藏出現(xiàn)的問(wèn)題,所以要對(duì)子控制器進(jìn)行添加、移除管理解決。
二、父子控制器的addChild添加、移除正確管理
主控制器mainVC
// 在主控制器點(diǎn)擊 tab_A 切換子控制器
if title == "tab_A" {
// 添加子控制器1
let squareVC = UIViewController()
// 將VC添加到控制器上,建立父子關(guān)系,這時(shí)可以通過(guò)`parentViewController`訪問(wèn)到父控制器;調(diào)用`addChildViewController`系統(tǒng)會(huì)自動(dòng)調(diào)用`willMoveToParentViewController:`
addChild(squareVC)
// 將VC控制器的view添加到父控制器上
view.addSubview(squareVC.view)
// 調(diào)用VC的`didMoveToParentViewController`通知VC完成了父子關(guān)系建立。
squareVC.didMove(toParent: self)
// 移除子控制器2
let myVC = UIViewController()
// 通知子控制器即將解除父子關(guān)系
myVC.willMove(toParent: nil)
// 將VC的view從父控制器移除
myVC.view.removeFromSuperview()
// 通過(guò)`removeFromParentViewController`真正解除父子關(guān)系,并且系統(tǒng)會(huì)調(diào)用`didMoveToParentViewController:`
myVC.removeFromParent()
}
// 在主控制器點(diǎn)擊 tab_B 切換子控制器
else if title == "tab_B" {
// 添加子控制器2...
// 移除子控制器1...
// 原理同上
}
1. 子控制器添加:
- 將VC添加到控制器上,建立父子關(guān)系,這時(shí)可以通過(guò)
parentViewController訪問(wèn)到父控制器;調(diào)用addChildViewController系統(tǒng)會(huì)自動(dòng)調(diào)用willMoveToParentViewController:。 - 將VC控制器的view添加到父控制器上。
- 調(diào)用VC的
didMoveToParentViewController通知VC完成了父子關(guān)系建立。
2. 子控制器移除:
- 通知子控制器即將解除父子關(guān)系。
- 將VC的view從父控制器移除。
- 通過(guò)
removeFromParentViewController真正解除父子關(guān)系,并且系統(tǒng)會(huì)調(diào)用didMoveToParentViewController:。
最終修改后具體實(shí)現(xiàn):

tapd_44062861_1714123000_599.png
最最最后,完結(jié)撒花

告辭.jpeg