Reputation: 6547
I have 2 simple view as following
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
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