LynAs
LynAs

Reputation: 6547

How to access ViewController component from PageViewController

I have 2 simple view as following

enter image description here

first one is PageView second one is simple viewController with an image view on top

viewController code as follows

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        imgView.image = UIImage(named: "dog0")
    }
}

When i run this view controller as initial view controller. it works fine. it shows the image properly

but when i do the same from a page view controller with following code

class PageViewController: UIPageViewController, UIPageViewControllerDataSource {

    let imageNames = ["dog0","dog1","dog2"]
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        let eachView = ViewController()
        eachView.imageName = imageNames.first
        let viewControllers = [eachView]
        setViewControllers(viewControllers, direction: .forward, animated: true, completion: nil)
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        return nil
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        return nil
    }


}

and

class ViewController: UIViewController {
    var imageName : String? {
        didSet {
            imgView.image = UIImage(named: imageName!)
        }
    }
    @IBOutlet weak var imgView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
    }
}

I get following error

fatal error: unexpectedly found nil while unwrapping an Optional value

on line

imgView.image = UIImage(named: imageName!)

What is the problem & how to fix this ?

Upvotes: 0

Views: 309

Answers (1)

matt
matt

Reputation: 535557

The problem is this line:

let eachView = ViewController()

This creates a ViewController instance "out of thin air", without any associated main view. Thus, when the view loads, it is empty. Thus, there is no image view in the view, and imgView is nil. Thus, when you refer to imgView as if it were not nil (trying to set its image), you crash.

The correct procedure is to instantiate the ViewController that you have designed in the storyboard. That ViewController instance has an image view in its view, because you designed it (you put it there), and it has an imgView outlet, as you already know, again because you designed it (you put it there).

To obtain that ViewController instance, get a reference to the storyboard (probably as self.storyboard) and call instantiateViewController(withIdentifier:). Of course you will have to have assigned an identifier to this ViewController instance in the storyboard.

Then you need to rewrite ViewController like this:

class ViewController: UIViewController {
    var imageName : String? {
        didSet {
            imgView?.image = UIImage(named: imageName!)
        }
    }
    @IBOutlet weak var imgView: UIImageView? // note the question mark

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        imgView?.image = UIImage(named: imageName!) // note the repeat
    }
}

The reason is that you now have a timing problem: you are setting imageName before the view loads, so imgView still hasn't hooked up to its outlet. By moving the key line into viewDidLoad, you make sure that we do this after we actually have a view and an outlet.

Upvotes: 2

Related Questions