Search code examples
iosswiftuiviewcontrolleruilabeluipageviewcontroller

Same UIViewControllers in UIPageViewController


I need a UIPageViewController to display as many UIViewControllers as the data available in an array. Let's say I have an array of Int and for each of this Int I want a UIViewController to display one of them in a UILabel. To accomplish this I've created in my Main storyboard both the UIPageViewController and UIViewController with its UILabel.

This is the code I've written for the UIPageViewController:

import UIKit
import RealmSwift

class PageViewController: UIPageViewController, UIPageViewControllerDataSource {

    lazy var subViewControllers: [UIViewController] = {
        return [
            self.createNewVC(withName: "CounterViewController"),
            self.createNewVC(withName: "CounterViewController"),
            self.createNewVC(withName: "CounterViewController")
        ]
    }()

    var dataArray: [Int] = [30, 134, 345]

    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        setViewControllers([subViewControllers[0]], direction: .forward, animated: true, completion: nil)
    }

    // Creates a new ViewController
    func createNewVC(withName name: String) -> UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: name)
    }

    // Returns the previous ViewController
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        let currentIndex: Int = subViewControllers.index(of: viewController) ?? 0

        if (currentIndex <= 0) {
            return nil
        }

        if let previous = subViewControllers[currentIndex - 1] as? CounterViewController {
            previous.daysLeftLabel.text = String(dataArray[currentIndex])
            return previous
        } else {
            return nil
        }
    }

    // Returns the next ViewController
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        let currentIndex: Int = subViewControllers.index(of: viewController) ?? 0

        if (currentIndex >= subViewControllers.count - 1) {
            return nil
        }

        if let next = subViewControllers[currentIndex + 1] as? CounterViewController {
            next.daysLeftLabel.text = "0"
            return next
        } else {
            return nil
        }
    }

}

and this is the code for the UIViewController

import UIKit

class CounterViewController: UIViewController {

    @IBOutlet weak var daysLeftLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

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

}

NB: "CounterViewController" is also the UIViewController StoryBoardID

The problem is that when I scroll for the first time to the right the app crashes at this line next.daysLeftLabel.text = "0" saying that it found a nil value while unwrapping Optional.

What am I doing wrong here?

Also I want to take the opportunity to ask something. In this case, as you may have guessed, I am using a UIPageViewController which holds the same UIViewControllers but with different data displayed, which is the best way to accomplish this? Am I doing it correctly or there is an easier and cleaner way?


Solution

  • This line crashes

    next.daysLeftLabel.text = "0"
    

    because daysLeftLabel is nil until the VC loads , you need

    class CounterViewController: UIViewController {
      @IBOutlet weak var daysLeftLabel: UILabel!
       var sendedText = ""
        override func viewDidLoad() {
         super.viewDidLoad()
          daysLeftLabel.text = sendedText
          // Do any additional setup after loading the view.
        }
    
    }
    

    Then use

    next.sendedText = "0"