You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:27:18