Swift - UIPageViewController 总是重复第二个视图控制器

4
设置:我试图创建一个ViewController,其中包含一个嵌入式UIPageViewController,其具有4个页面,每个页面都是它们自己的ViewController。
问题:当滚动时,第二个视图总是重复出现。例如,使用View1、View2、View3、View4,滚动会显示View1、View2、View2、View3、View4,然后向后滚动会有这个顺序View4、View3、View3、View2、View1,尽管页面控件是准确的。
我看了很多在线教程,包括这里这里的答案。
以下是我的page view controller类:
import UIKit

class HostGamePageViewController: ROLViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {

  // Constants
  let ViewControllers: NSArray = ["HostGameTest1", "HostGameTest2", "HostGameTest3", "HostGameTest4"]

  // Properties
  var pageViewController: UIPageViewController!
  var currentViewController: String!

  // UI
  @IBOutlet var pageControl: UIPageControl!

  override func viewDidLoad() {
    super.viewDidLoad()

    pageViewController = storyboard?.instantiateViewControllerWithIdentifier("HGPageViewController") as? UIPageViewController
    pageViewController.delegate = self
    pageViewController.dataSource = self

    let startingViewController = viewControllerAtIndex(0)!
    pageViewController.setViewControllers([startingViewController], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: {done in })

    addChildViewController(pageViewController)
    view.addSubview(pageViewController.view)
    pageViewController.view.frame = view.bounds
    pageViewController.didMoveToParentViewController(self)
    view.gestureRecognizers = pageViewController.gestureRecognizers

    // Setup page controls
    pageControl.numberOfPages = ViewControllers.count
    view.bringSubviewToFront(pageControl)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }

  // Get the index of the current page view
  func indexOfViewController() -> Int {
    if currentViewController != nil {
      return ViewControllers.indexOfObject(currentViewController)
    }

    return NSNotFound
  }

  // Get the view controller of the given index
  func viewControllerAtIndex(index: Int) -> UIViewController? {
    if ViewControllers.count == 0 || index >= ViewControllers.count {
      return nil
    }

    pageControl.currentPage = index
    currentViewController = ViewControllers[index] as String

    return storyboard?.instantiateViewControllerWithIdentifier(currentViewController) as? ROLViewController
  }

  // Handle clicks on the page control
  @IBAction func pageControlClick(sender: UIPageControl) {
    var direction: UIPageViewControllerNavigationDirection

    if sender.currentPage < indexOfViewController() {
      direction = UIPageViewControllerNavigationDirection.Forward
    } else {
      direction = UIPageViewControllerNavigationDirection.Reverse
    }

    if let viewController = viewControllerAtIndex(sender.currentPage) {
      pageViewController.setViewControllers([viewController], direction: direction, animated: false, completion: nil)
    }
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    var index = indexOfViewController()

    if index == 0 || index == NSNotFound {
      return nil
    }

    index--
    return viewControllerAtIndex(index)
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    var index = indexOfViewController()

    if index == NSNotFound {
      return nil
    }

    index++
    if index == ViewControllers.count {
      return nil
    }

    return viewControllerAtIndex(index)
  }

}

这是我的故事板截图链接:http://f.cl.ly/items/0V3W133Q34170q39393Q/Image%202014-09-11%20at%2011.49.44%20AM.png 我是否设置了错误的数据源?我在某处读到,UIPageViewController通过将动画关闭来进行一些缓存,这是所谓的解决方法,但对我没有任何作用。非常感谢您的帮助。谢谢!

1
我找到了一个解决方法。不是从beforeView和afterView调用中返回HostGameView1、HostGameView2等,而是始终返回一个包装视图控制器,然后告诉该包装视图控制器要呈现哪个视图。这似乎有效。 - hirsch
1个回答

5

我遇到了一个非常类似的问题(不是用Swift,在obj-c中,有3个视图控制器,中间那个重复了一次:“0,1,1,2”)。结果证明这完全是关于页面视图控制器数据源方法的问题...

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController;
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController;

我还没有深入研究过Swift(也没有兴趣),但是通过伪代码阅读,我认为你使用控制器作为UIPageViewControllerDataSource,并且使用其中包含的变量来限制“before”和“after”关键方法的范围(在Swift中)。这正是我所做的更改和解决问题的方法。我英语不太好,但我希望你能理解我的最后一句话。我使用的修复方法基于这个教程。在我的情况下,我在所有三种情况下使用了“UINavigationViewControllers”视图控制器,因此我创建了一个“NavigationWrapperViewController”,它具有一个属性:
@property(assign, nonatomic) NSUInteger index;

然后,在检查关键的数据源方法中的边界限制时进行操作(只展示一个,对于另一个也使用相同的技术):

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
   NSUInteger indice = ((NavigationWrapperViewController*)viewController).index;
   if ((indice == 0) || (indice == NSNotFound)) {
       return nil;
   }    
   return [self viewControllerAtIndex:(--indice)];
}

在实例化视图控制器时,在 viewControllerAtIndex 中,返回视图控制器之前不要忘记正确设置该属性:
NavigationWrapperViewController *wrapperViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.ViewControllers[index]];
wrapperViewController.index = index;

return wrapperViewController;

细微的区别在于,当前显示的视图控制器的索引是由当前视图控制器存储的(使用一个简单的包装器,该类完全是为此目的而创建的,它只在其.h文件中实现了一个属性)而不是由UIPageViewControllerDataSource负责的类存储。
这解决了我的问题,也许是某种线程相关问题影响了获取的当前视图控制器索引,并导致了整个重复视图控制器的问题。
如果你愿意尝试一下,希望能有所帮助!

感谢您的详细回复!拥有一个包装视图来保存当前对象数据似乎确实可以解决这个问题。 :) - hirsch

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