When I try to create an instance of a UIViewController
in Swift
, 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????
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)
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.
let Vc = UIViewController()
vc.view = yourview
or add above vc to View as ChildviewController
configureChildViewController(vc,onView:yourview in Viewcontroller)
Use this Extension for UiViewController
extension UIViewController {
func configureChildViewController(childController: UIViewController, onView: UIView?) {
var holderView = self.view
if let onView = onView {
holderView = onView
}
addChildViewController(childController)
holderView.addSubview(childController.view)
constrainViewEqual(holderView, view: childController.view)
childController.didMoveToParentViewController(self)
}
func scatterChildViewController(childController: UIViewController) {
childController.willMoveToParentViewController(self)
childController.view.removeFromSuperview()
childController.removeFromParentViewController()
}
func constrainViewEqual(holderView: UIView, view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
//pin 100 points from the top of the super
let pinTop = NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal,
toItem: holderView, attribute: .Top, multiplier: 1.0, constant: 0)
let pinBottom = NSLayoutConstraint(item: view, attribute: .Bottom, relatedBy: .Equal,
toItem: holderView, attribute: .Bottom, multiplier: 1.0, constant: 0)
let pinLeft = NSLayoutConstraint(item: view, attribute: .Left, relatedBy: .Equal,
toItem: holderView, attribute: .Left, multiplier: 1.0, constant: 0)
let pinRight = NSLayoutConstraint(item: view, attribute: .Right, relatedBy: .Equal,
toItem: holderView, attribute: .Right, multiplier: 1.0, constant: 0)
holderView.addConstraints([pinTop, pinBottom, pinLeft, pinRight])
}
}