0

I recently set up a ContainerView with a PageViewController that cycles through views (images) as a sort of banner on top of a TableView that I have. Now, I'm having difficulty hooking that up to an NSTimer (so that it will cycle through the views/images automatically). Everything works, except for the timer piece that I've tried to hook up. I've tried to convert some Objective-C tutorials/SO questions but am still having difficulty.

I have looked at this: Set timer to UIPageViewController, but I can't get that provided code to work for me at all (nor any variation of it).

See below for my code:

class ImageSwapViewController: UIPageViewController {

    private(set) lazy var orderedViewControllers: [UIViewController] = {
        return [self.newColoredViewController("First"),
        self.newColoredViewController("Second"),
        self.newColoredViewController("Third")]
    }()

    private func newColoredViewController(order: String) -> UIViewController {
        return UIStoryboard(name: "Main", bundle: nil) .
        instantiateViewControllerWithIdentifier("\(order)ViewController")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        self.dataSource = self

        if let firstViewController = orderedViewControllers.first {
        setViewControllers([firstViewController],
            direction: .Forward,
            animated: true,
            completion: nil)
    }

        NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: #selector(ImageSwapViewController.animation), userInfo: nil, repeats: true)
    }

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

    func animation() {
        [NEED HELP WITH WHAT GOES HERE]
    }
}

extension ImageSwapViewController : UIPageViewControllerDataSource {

    func pageViewController(pageViewController: UIPageViewController,
        viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
            guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
                return nil
            }

            let previousIndex = viewControllerIndex - 1

            guard previousIndex >= 0 else {
                return orderedViewControllers.last
            }

            guard orderedViewControllers.count > previousIndex else {
                return nil
            }

            return orderedViewControllers[previousIndex]
    }

    func pageViewController(pageViewController: UIPageViewController,
        viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
            guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
                return nil
            }

            let nextIndex = viewControllerIndex + 1
            let orderedViewControllersCount = orderedViewControllers.count

            guard orderedViewControllersCount != nextIndex else {
                return orderedViewControllers.first
            }

            guard orderedViewControllersCount > nextIndex else {
                return nil
            }

            return orderedViewControllers[nextIndex]
    }

}

Any help is greatly appreciated.

Community
  • 1
  • 1
skind
  • 173
  • 1
  • 2
  • 17
  • Possible duplicate of http://stackoverflow.com/questions/29358685/set-timer-to-uipageviewcontroller – gotnull Apr 26 '16 at 04:46
  • I hadn't seen that one. I'm reviewing now. Thanks! (I'll delete this if so) – skind Apr 26 '16 at 04:50
  • @gotnull I'm probably just an idiot but I'm having trouble getting that answer to work with my given code. – skind Apr 26 '16 at 05:53

1 Answers1

1

A couple of notes:

1) The general idea is that you need to set up a timer in some reasonable place--viewWillAppear is a common location, and remember to invalidate it when the view is no longer displaying (as in viewWillDisappear). Failing to do so may result in memory growth because the run loop holds a strong reference to the target--in this case, self. I'd recommend moving your NSTimer.scheduledTimer... invocation to viewWillAppear.

2) The animation code above is pretty simple. Basically, you need to get the current "page", find out what the next "page" should be, and then ask your UIPageViewController to display that next "page".

func animation() {
    guard let currentViewController = viewControllers?.first else {
        return
    }

    // Use delegate method to retrieve the next view controller
    guard let nextViewController = pageViewController(self, viewControllerAfterViewController: currentViewController) else {
        return
    }
    setViewControllers([nextViewController], direction: .Forward, animated: true, completion: nil)
}

You could also simplify your before and after methods slightly:

func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    guard let i = orderedViewControllers.indexOf(viewController) else {
        return nil
    }
    let nextIndex = (i + 1) % AutoAnimatingPageViewController.colors.count
    return orderedViewControllers[nextIndex]
}

func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    guard let i = orderedViewControllers.indexOf(viewController) else {
        return nil
    }
    let prevIndex = (i - 1) < 0 ? AutoAnimatingPageViewController.colors.count - 1 : (i - 1)
    return orderedViewControllers[prevIndex]
}
Palpatim
  • 9,074
  • 35
  • 43
  • This works absolutely perfect. Didn't realize how easy it was, but now looking over your code it makes total sense. Thank you. Also, thanks for the simplification of the VCAfterVC/Before code. – skind Apr 28 '16 at 03:40
  • Glad it worked! Please also note my comment about invalidating the timer during the VC lifecycle. Developing that habit now will save you a lot of grief in the future. :) – Palpatim Apr 28 '16 at 13:58
  • I noticed that and actually added some code to invalidate it. Initially I didn't (just to test your code) and quickly saw how it was screwing with the view as I moved away and back to it. Great advice and thanks for the heads up. – skind Apr 28 '16 at 14:30
  • Every time animation function going to same page.For example if we have 3 pages, then every time it will going to 2nd page only. – Tushar Lathiya Aug 09 '18 at 05:51