Avt
Avt

Reputation: 17043

IBOutlets from xib are not initialised if I run an app on iOS8 Simulator

I have build an app using XCode 7 GM (base SDK - iOS9). It works perfectly if I run it on iOS 9 Simulator but if I try to run it on iOS8 it fails here:

@IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = NSLocalizedString("Home", comment: "Home")
    collectionView.registerNib(UINib(nibName: "PTHomeCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "PTHomeCollectionViewCell")
}

with an error

fatal error: unexpectedly found nil while unwrapping an Optional value

because a collectionView is nil: enter image description here

Of course I have doubled checked that connection in IB is established: enter image description here

Could anyone please tell me why collectionView is nil here?

Upvotes: 2

Views: 441

Answers (3)

Alexander Doloz
Alexander Doloz

Reputation: 4188

This issue is highlighted in Matt Neuburg's book Programming iOS 8. This happens because iOS 8 expects xib names to be prefixed with module name which is the same as name of project in this case. For example, if you have MyViewController in your project MyProject, it will expect to find the xib named MyProject.MyViewController.xib. To workaround this, override nibName in your view controller:

override var nibName: String? { 
    return "\(self.dynamicType)"
}

Upvotes: 1

Hugo
Hugo

Reputation: 994

How are you instantiating your view controller?

Instantiating via viewController = MyViewController() will crash in iOS8.x when accessing the IBOutlets (though it works ok in iOS9.3, and presumably in iOS9.x)

Instantiating the view controller with viewController = MyViewController(nibName: "MyViewController", bundle: nil) should work no matter the version of iOS.

See this other posting for reference: All my IBOutlet are nil in viewDidLoad

Upvotes: 0

Avt
Avt

Reputation: 17043

I was able to fix this issue by adding

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    let name = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
    super.init(nibName: nibNameOrNil ?? name, bundle: nibBundleOrNil)
}

to the view controller class. But why it works this way? Is there another way to fix this issue?

Update: It is an Swift view controllers feature that is very similar to a bug. Check Can't Load UIViewController XIB file in Storyboard in Swift and Are view controllers with nib files broken in ios 8 beta 5?

It is fixed in iOS 9.4 but if you need iOS 8 and earlier support you still need to use workarounds.

Upvotes: 3

Related Questions