Unable to programatically create a UIViewController in Swift
Solution 1
As you've pointed out: As long as the nib name matches the class name in objective-C, even if you don't specify a nib name when initializing the view controller, the view controller will still look for the nib file whose name matches the name of the view controller class.
But for some reason (perhaps it's a bug), this is not the case in Swift.
Instead of writing:
let vc = ImageViewController()
You have to explicitly specify an interface when initializing the view controller:
let vc = ImageViewController(nibName: "nibName", bundle: nil)
Solution 2
As a convenience, I came up with this workaround so that I don't have to use the longer initializer everywhere. I have a BaseViewController
that all my controllers extend.
init () {
let className = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last
super.init(nibName: className, bundle: NSBundle(forClass: self.dynamicType))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Note, using NSBundle(forClass: self.dynamicType)
takes care of namespacing in different targets.
Then when I want to instantiate a ViewController
, I use MyViewController()
as you could in Objective-C.
cfischer
Updated on June 11, 2022Comments
-
cfischer almost 2 years
When I try to create an instance of a
UIViewController
inSwift
, all the inherited initialisers are unavailable, even though I didn't define any designated inits in the view controller (or anything else, FWIW).Also, if I try to display it by making it the root view controller, it never gets displayed:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. window = UIWindow(frame: UIScreen.mainScreen().bounds) window?.makeKeyAndVisible() window?.backgroundColor = UIColor.greenColor() let vc = ImageViewController() window?.rootViewController = vc return true }
The code for the view controller is just Xcode's template:
import UIKit class ImageViewController: UIViewController { 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. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ }
Anybody knows what's going on????
-
cfischer over 9 yearsOK, now it kinda works. :-) If I call the nibName:,bundle: initializer explicitly (even though autocomplete won't recognise it) AND I pass the name of the xib file, it works. However, that's not the expected behaviour: If I just call init or init(nibName:nil, bundle:nil) it should pick up the name of the xib file by looking at the name of the class. And it doesn't. :-(
-
Lyndsey Scott over 9 years@cfisher But where is your init?
-
cfischer over 9 yearsI didn't define ANY inits in the view controller. The code is exactly the one provided by Xcode's template. It's the one included at the end of the question. I'm calling it from my ApplicationDelegate, in the application did finish loading with options method.
-
Lyndsey Scott over 9 years@cfisher OK, then that's your problem. No matter what, whether it's in your app delegate or in a custom init you 100% have to explicitly pass/include the name of your xib file. It's not true that "it should pick up the name of the xib file by looking at the name of the class." Even Apple lists the above method as the "designated initialized for the view controller class" in their docs: developer.apple.com/library/ios/Documentation/UIKit/Reference/…:
-
cfischer over 9 yearsinit(nibName nibName: String?, bundle nibBundle: NSBundle?) is indeed the designate initialisers for UIViewControllers. However, you do NOT have to specify a name for the nib file, unless the name of the nib file is different from the name of the class.
-
cfischer over 9 yearsFrom the Apple Docs: "However, if you do not specify a nib name, and do not override the loadView method in your custom subclass, the view controller searches for a nib file using other means. Specifically, it looks for a nib file with an appropriate name (without the .nib extension) and loads that nib file whenever its view is requested. " developer.apple.com/library/ios/Documentation/UIKit/Reference/…
-
cfischer over 9 yearsThat code, if written in Objective C, compiles and runs fine. So there's something weird going on when using Swift...
-
Lyndsey Scott over 9 years@cfisher Hm... I'm looking into it.
-
Lyndsey Scott over 9 years@cfisher Yeah, I've gotten the same results with my own code and have updated my answer accordingly for future answer seekers. Perhaps you should submit a bug report to Apple.
-
cfischer over 9 yearsThanks anyway, you gave me at least a workaround! :-)