How to connect to custom UIViewContoller with xib on Storybord - ios

I created MyViewController.swift and MyViewController.xib files.
Then I put label on xib file.
I droped to UIViewController on the Storyboad.
Then I changed it's 'Custom Class' UIViewController to MyViewController.
But it does not appear the label which on xib.
How can I show the MyViewController with xib?
Should I write some code in MyViewController to relate with xib?
I just want to reuse components with xib in my app.

Your MyViewController.swift file should at least contain the declaration for the class as this :
import UIKit
class MyViewController: UIViewController {
}
inside your class declaration you will also need the following if you want to load your view from the xib :
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Custom initialization
}
Finally in order to access your label you can create an IBOutlet in your class declaration like this:
#IBOutlet weak var myLabel: UILabel?
Then you will be able to connect it using Interface Builder and access it in your code

Related

Nil Enherited outlet on the subclass

I've defined a base class with an outlet and attached the outlet to the view in the nib file
class BaseController: UIViewController {
#IBOutlet weak var myView : UIView!
and then created a subclass
class SubViewController: BaseController {
override func viewDidLoad() {
myView.backgroundColor = UIColor.red //The app crashes here
When i call BaseController() it view appears, but when I call SubViewController() the app crashes because myView is nil. The files owner on the nib file is BaseController.
Try to create custom initializer in your subclass:
init() {
super.init(nibName: "BaseController", bundle: nil)
}

iOS Swift subclassing ViewController initialized by xib (nib) file

I have one base class
MyViewController: UIViewController
initialized by MyViewController.xib with some outlets. I only have set File Owner class in MyViewController.xib to MyViewController, no any init methods in MyViewController.swift (all inherited from UIViewController), and following line works just as expected:
let vc = MyViewController()
view property is set, outlets is set.
I wish to subclass MyViewController:
SecondViewController: MyViewController
{
override init()
{
super.init()
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
}
Now I expect that line
let vc = SecondViewController()
will create view controller with view and outlets inherited from MyViewController, but all outlets in vc are nil. Looks like MyViewController.xib file is now missed. What am I doing wrong?
You can't extend the xib file. The SecondViewControllershould have its own xib file and its own outlets. You may define the common UI components in the base class MyViewController and for each xib you create, link the ui components directly to the base class.
For example, if you have a common custom back button in all view controller, add the outlet definition in the base class and for each xib file add the UIButton and set its outlet to the base class.

Convenience initialiser for UIViewController subclass with instance from nib?

I am trying to initialise a subclass of UIViewController called TestController. I have this swift class:
class TestController : UIViewController {
let testString : String
#IBOutlet weak var test: UITextField!
required init(withString string: String) {
self.testString = string
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I also have a nib file called TestController,
inside it is an instance of UIViewController. The file's owner is none (NSObject in grey) and the class of the UIViewController instance in designer is set in the identity inspector to TestController. There is a UITextField instance as outlet.
The problem is the controller is not initialised from the nib (I think), and the textField outlet is nil.
My goal is to allow initialization of controller's instance from nib programmatically, via the custom initialiser. What am I doing wrong?
You have two problems: First, your nib (or xib) is not created properly (you shouldn't see TestController in interface builder). The easiest way to fix this is to recreate it: New File->Cocoa Touch Class->Create Subclass of UIViewController, and don't forget to check Also Create a XIB file
The second problem is that you're not specifying what nib you want to load. You should specify it in nibName parameter of the initializer:
super.init(nibName: "NewlyCreatedXib", bundle: nil)
When you fix both issues, I believe your code will work properly.

Double Initialization Of UIViewController's Subclass Member in Swift

I wanted to make a custom container view controller and added some members to the subclass of UIViewController. When I try to init it from the app delegate by using following code:
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = CustomContainerViewController()
self.window?.makeKeyAndVisible()
all the members in CustomContainerViewController were initialized twice.
Here is CustomContainerViewController's code:
class CustomContainerViewController: UIViewController {
let tabBar = CustomTabBar()
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil?, bundle: nibBundleOrNil?)
}
}
Here is CustomTabBar's code:
class CustomTabBar: UIView {
override init(){
println("init")
super.init()
}
override init(frame: CGRect) {
println("initWithFrame:")
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
println("initWithCoder:")
super.init(coder: aDecoder)
}
}
Whenever you init the CustomContainerViewController from the app delegate by using the code previously mentioned, is always prints "init", "initWithFrame" twice.
Incorrect designated initializer used.
UIViewController has only one designated initializer init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?).
As its comment says
The designated initializer. If you subclass UIViewController, you must call the super implementation of this method, even if you aren't using a NIB. (As a convenience, the default init method will do this for you, and specify nil for both of this methods arguments.) In the specified NIB, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view. If you invoke this method with a nil nib name, then this class' -loadView method will attempt to load a NIB whose name is the same as your view controller's class. If no such NIB in fact exists then you must either call -setView: before -view is invoked, or override the -loadView method to set up your views programatically.
So whenever you override the init() method of UIViewController, once you call super, UIViewController's implementation would call init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) on behalf of you. So all the members in your UIViewController's subclass were initialized twice.
To solve this problem, use following code in the app delegate
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = CustomContainerViewController(nibName: nil, bundle: nil)
self.window?.makeKeyAndVisible()
And never call the init() method of UIViewController or override this method in subclasses.

Could not load Nib in bundle - Wrong nibname in error

I'm trying to push a ViewController's view initialized with a xib file. To do so, I'm calling the initializer of my controller which calls himself the initwithnibname:bundle: to load the correct xib file.The problem is that I'm getting the following error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: [...] with name 'BYZ-38-t0r-view-x4c-fw-L1g'
The nib name in the error does not match the provided nib name in the initializer call.
Here is my code :
ViewController declaration/initialization
let connexionViewController = ConnexionViewController()
self.view.addSubview(connexionViewController.view) // Exception thrown on this line
ViewController code
import Foundation
import UIKit
class ConnexionViewController: UIViewController {
#IBOutlet var validateButton: UIButton!
#IBOutlet var usernameTextField: UITextField!
required init(coder: NSCoder) {
super.init(coder: coder)
}
override init() {
super.init(nibName: "ConnexionViewController", bundle: nil)
}
override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The xib file's name match the string provided to the initializer and the xib is added to the build phases for the actual target.
ViewController * pvc = [[ViewController alloc]initWithNibName:NSStringFromClass([ViewController class]) bundle:nil];
I was loading nib this way to avoid strings.
This in turn started returning nib name as myproject.ViewController on adding swift compatibility to existing objC project for Mix and Match.
To sort this, either use the below kind of code or do string processig to crop the string till .
ViewController * pvc = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
Hope this helps someone in future.
It seems that the navigation controller wasn't fully initialized when the new controller was pushed. I changed the location of the call and it now works fine.

Resources