Swift iOS开发:子视图v2显示时重载失败,寻求解决方案
嘿,我明白你遇到的问题了——这种用ScrollView做页面切换时子VC提前加载的情况很常见,我来给你分析下原因和解决办法!
问题根源
你现在的代码里,一开始就把v2的view添加到ScrollView里了,哪怕它初始在屏幕外,UIKit还是会立刻加载这个view并走完它的生命周期(比如viewDidLoad)。至于viewWillAppear没生效,是因为UIKit判断一个VC的view是否“即将显示”,是看它的view是否被添加到视图层级且window属性存在——你的v2.view从一开始就在ScrollView里,window属性一直有,所以viewWillAppear只会在添加时调用一次,不会在滚动到它的时候触发。
解决方案
方案一:延迟加载v2的View(推荐,节省内存)
这种方法是等用户滚动到接近v2的位置时,再把v2的view添加到ScrollView,这样它的生命周期方法才会在此时触发,你可以把加载逻辑放在viewDidLoad里,或者手动触发刷新。
// 先把v2改成懒加载,初始化时只关联父VC,不添加view lazy var v2: cityChart1VC = { let vc = cityChart1VC(nibName: "cityChart1VC", bundle: nil) self.addChild(vc) vc.didMove(toParent: self) return vc }() override func viewDidLoad() { super.viewDidLoad() // 初始化并添加v1 let v1 = assetType1VC(nibName: "assetType1VC", bundle: nil) self.addChild(v1) self.scrollView.addSubview(v1.view) v1.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.scrollView.frame.height) v1.didMove(toParent: self) // 设置ScrollView的内容大小 self.scrollView.contentSize = CGSize(width: self.view.frame.width * 2, height: self.scrollView.frame.height) self.scrollView.delegate = self } // 实现UIScrollViewDelegate,监听滚动 func scrollViewDidScroll(_ scrollView: UIScrollView) { let screenWidth = self.view.frame.width let currentOffsetX = scrollView.contentOffset.x // 当滚动到距离v2还有50pt时,判断是否已添加view if currentOffsetX >= screenWidth - 50 && v2.view.superview == nil { v2.view.frame = CGRect(x: screenWidth, y: 0, width: screenWidth, height: scrollView.frame.height) scrollView.addSubview(v2.view) // 如果需要手动触发刷新,这里可以调用v2的方法 // v2.reloadChartData() } }
方案二:用UIPageViewController(更符合iOS最佳实践)
UIPageViewController天生支持页面的懒加载,只有当页面即将显示时才会加载对应的VC,而且它已经帮你处理了滚动切换的逻辑,不用自己管理ScrollView的contentOffset。
override func viewDidLoad() { super.viewDidLoad() // 初始化PageViewController let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal) pageVC.dataSource = self pageVC.delegate = self // 设置初始页面为v1 let v1 = assetType1VC(nibName: "assetType1VC", bundle: nil) pageVC.setViewControllers([v1], direction: .forward, animated: false) // 添加到当前视图 self.addChild(pageVC) self.view.addSubview(pageVC.view) pageVC.view.frame = self.view.bounds pageVC.didMove(toParent: self) } // 实现UIPageViewControllerDataSource,提供前后页面 extension YourParentVC: UIPageViewControllerDataSource { func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { if viewController is cityChart1VC { return assetType1VC(nibName: "assetType1VC", bundle: nil) } return nil } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { if viewController is assetType1VC { return cityChart1VC(nibName: "cityChart1VC", bundle: nil) } return nil } } // 实现UIPageViewControllerDelegate,在页面即将显示时刷新 extension YourParentVC: UIPageViewControllerDelegate { func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { if let targetVC = pendingViewControllers.first as? cityChart1VC { // 在这里触发v2的重新加载逻辑 targetVC.reloadChartData() // 替换成你实际的刷新方法 } } }
方案三:仅在显示v2时刷新数据(如果不需要延迟加载view)
如果你不在乎v2的view提前加载,只是想在它显示时重新加载数据,可以监听ScrollView的停止滚动事件,判断当前显示的是v2页面时触发刷新:
override func viewDidLoad() { super.viewDidLoad() // 你的原有初始化代码,保留添加v1和v2的逻辑 let v1 = assetType1VC(nibName: "assetType1VC", bundle: nil) let v2 = cityChart1VC(nibName: "cityChart1VC", bundle: nil) self.addChild(v1) self.addChild(v2) self.scrollView.addSubview(v1.view) self.scrollView.addSubview(v2.view) v1.didMove(toParent: self) v2.didMove(toParent: self) let screenWidth = self.view.frame.width v2.view.frame = CGRect(x: screenWidth, y: 0, width: screenWidth, height: self.scrollView.frame.height) self.scrollView.contentSize = CGSize(width: screenWidth * 2, height: self.scrollView.frame.height) self.scrollView.delegate = self } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let currentPage = scrollView.contentOffset.x / scrollView.frame.width // 当滚动到第二页(v2)时 if currentPage == 1 { // 调用v2的刷新方法 (scrollView.subviews.compactMap { $0.next as? cityChart1VC }.first)?.reloadData() } }
内容的提问来源于stack exchange,提问作者Felwah
相关产品推荐
相关产品推荐

