如何使UIPageViewController像UITableView一样重用控制器?

25

我需要一种方法使UIPageViewController可以重用控制器来节省内存,因为我有大量页面要展示! 我已经实现了UIPageViewController的基本功能,但无法将控制器重用,请给予建议!

2个回答

16

为了解决我当前项目中的这个问题,我将作为UIPageViewController页面创建的所有视图控制器缓存到一个Set中。每当UIPageViewController从其数据源请求新的视图控制器时,我通过检查parentViewController属性来过滤出未使用过的缓存;如果没有可用的未使用的视图控制器,则会创建一个新的视图控制器。

我的UIPageViewController和缓存的设置类似于以下内容:

class MyPageViewController: UIPageViewController {
    private var reusableViewControllers = Set<MyViewController>()
    init() {
      super.init(/* ... */)
      self.dataSource = self

      let initialViewController = self.unusedViewController()

      // Configure the initial view controller
      // ...

      self.setViewControllers([ initialViewController ], 
                              direction: .Forward, 
                              animated: false, 
                              completion: nil)
    }

  // This function returns an unused view controller from the cache
  // or creates and returns a new one
  private func unusedViewController() -> MyViewController {
    let unusedViewControllers = reusableViewControllers.filter { $0.parentViewController == nil }
    if let someUnusedViewController = unusedViewControllers.last {
        return someUnusedViewController
    } else {
        let newViewController = MyViewController()
        reusableViewControllers.insert(newViewController)
        return newViewController
    } 
  }
}

数据源使用相同的函数来获取未使用的视图控制器:

extension MyPageViewController: UIPageViewControllerDataSource {
  func pageViewController(pageViewController: UIPageViewController,
                          viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        let nextViewController = unusedViewController()

        // Configure the next view controller for display
        // ...

        return nextViewController
    }
}

这是目前在数据库中水平滑动记录(每页一个记录)的最佳方式吗?在Android中,它已经以ViewPager的形式实现,并为您管理重用。 - Dale
1
谢谢。我正在使用if let someUnusedViewController = reuseableViewControllers.first(where: { $0.parentViewController == nil }) {这个代码,它可能会稍微更有效率一些。我正在使用数组而非集合。我发现在iOS 12.1上,该代码只构建三个视图控制器。 - PhoneyDeveloper
1
这是一个非常聪明的解决方案。虽然我有两个问题,如果使用set,如何确定您所在的页面索引以避免创建旋转木马效果。另外,作为一般性问题,在这种情况下使用UIPageViewController相比于全尺寸的collectionViewCell有什么优势? - TheRedCamaro3.0 3.0
你需要单独跟踪索引,例如通过将 viewController 向下转型为具有 index 属性的自定义 UIViewController 子类。你的第二个问题太广泛了,无法在评论中回答。你可能需要先阅读 UIPageViewControllerUICollectionView 的文档,然后如果仍有不清楚的地方,请发布一个新的、更具体的问题。 - Theo
2
谢谢。请问,您如何在UIPageViewController中保留UI状态呢?例如,在第二页,它有一个UICollectionView,其滚动位置为X。当我们向后滑动回到第二页时,如何恢复UICollectionView的X位置呢? - Cheok Yan Cheng

2
你可以使用ACReuseQueue来实现你想要的功能。它提供了一个队列,用于重复使用视图控制器,并可以使用UIPageViewController数据源方法从重复使用队列中出列VC。麻烦的部分是知道何时将它们放回重复使用队列。UIPageViewController不提供任何方法来知道这种情况,但还是有一种方法。UIPageViewController是一个容器VC,它使用VC容器API添加和删除其子视图控制器。如果您的VC正在从UIPageViewController中移除,则会收到didMoveToParentViewController:参数为nil。 使用此方法将自己重新添加到队列中。

棘手的部分在于知道何时将它们放回重用队列中。UIPageViewController并没有提供任何方法来知道何时会发生这种情况,但有一种方法可以解决。最后终于明白了,谢谢! - nolanw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接