Subclass a custom UIViewController (with xib) to add additional behaviour - ios

Here's the deal: I'm using the DEFacebookComposeViewController which is a custom subclass of a UIViewController. This subclass is using an xib to setup the user interface.
Now I want to add some additional GUI elements to DEFacebookComposeViewController so I figured I would create a subclass named something like MySubclassDEFacebookComposeViewController : DEFacebookComposeViewController and create a xib.
However the xib MySubclassDEFacebookComposeViewController.xib is not showing any of the GUI elements from DEFacebookComposeViewController.xib which I thought it would do since it's a subclass of that class.
So basically I'm just wondering what is the correct approach in adding new elements to a subclassed UIViewController and xib?

Copy the DEFacebookComposeViewController.xib and rename it to MySubclassDEFacebookComposeViewController.xib and edit it to your likings.
A UIViewController will look by default for a nib/xib with the same name (even without the controller part at the end) when created
From the docu of UIViewController:
If you use a nib file to store your view controller’s view, it is
recommended that you specify that nib file explicitly when
initializing your view controller. 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. Specifically, it looks (in order) for a nib file with
one of the following names:
If the view controller class name ends with the word “Controller”, as
in MyViewController, it looks for a nib file whose name matches the
class name without the word “Controller”, as in MyView.nib. It looks
for a nib file whose name matches the name of the view controller
class. For example, if the class name is MyViewController, it looks
for a MyViewController.nib file.
So you need to specify the nib you want to use or name it after the view controller. Since you want to add/modify the old nib you need a copy of it.
This is assuming that DEFacebookComposeViewController.xib does not have any IBOutlets by default. If it has you can modify the existing nib in viewDidLoad. Adding more subViews can always be accomplished aften the view is loaded regardless if there are IBOutlets.

Related

What is the difference between the different ways to navigate to a new UIViewController?

I seen 3 different implementations of how to init a UIViewController from a xib file. The method I have been using is to create a UIViewController and let Xcode create the xib file as well and then do:
let vc = CustomViewController()
navigationController?.push(vc, true)
This works and auto-layout works and everything is great.
Why are all the other examples I see online to use:
let vc = storyboard?.instantiateViewControllerWithIdentifier("CustomViewController") as CustomViewController
or:
let vc = HomeViewController(nibName: "HomeViewController", bundle: nil)
Am I missing something with the way I have been doing things? Please note I don't use segues and storyboard navigation. I separate all my view controllers in their own xib files.
Edit:
I am using the IB to layout my UI and link IBActions back to my source file. That is why I am confused why it works and why I never see this example posted anywhere. Is Xcode doing something behind the scenes to make it work?
I believe the reason why this works is stated in the Apple Developer Docs. Since I am just calling the default init of the view controller and not overriding loadView() it looks through the xib files for the ones matching the view controller's name as explain in below:
If you use a nib file to store your view controller's view, it is recommended that you specify that nib file explicitly when initializing your view controller. 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. Specifically, it looks (in order) for a nib file with one of the following names:
It looks for a nib file whose name matches the name of the view controller class. For example, if the class name is MyViewController, it looks for a MyViewController.nib file.
SourceL:
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621487-nibname?language=objc

How is it possible that Nib is loading?

I created new file and check Cocoa Touch Class -> Then I set subclass as UIViewController -> I mark "Also create XIB file".
It created simple UIViewController as expected, but here is my question becuase when I called:
present(MyViewController(), animated: true)
This shows MyViewController() as I wanted but how is it possible that I'm using simple init() and Nib is loaded?
I thought that I need to use different initalizer, how Swift is doing this?
It's not "Swift" doing this. It's the implementation of the UIViewController class. The same happens with Objective-C.
Start by reading the documentation for the UIViewController init(nibName:bundle:) method and the nibName property.
From the nibName documentation:
If you use a nib file to store your view controller's view, it is recommended that you specify that nib file explicitly when initializing your view controller. 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. Specifically, it looks (in order) for a nib file with one of the following names:
If the view controller class name ends with the word ‘Controller’, as in MyViewController, it looks for a nib file whose name matches the class name without the word ‘Controller’, as in MyView.nib.
It looks for a nib file whose name matches the name of the view controller class. For example, if the class name is MyViewController, it looks for a MyViewController.nib file.
Basically, in your case you use the default initializer meaning you specified nil for the nib name. So at runtime, the nib you created with the same name as the view controller class is automatically found and used.

Subclassing a View Controller

I have a single view aplicaition on xcode with several view controllers and xib files in it. I am trying to subclass a xib file's view controller called ViewControllerPg62 as a sub class of a view controller called ViewController. How can i do this?
Thanks in advance
Why are you working with XIB files? You should be using Storyboards.
I had to go back to an old project using XIBs to see how they worked.
In an XIB you should see an entry called "Placeholders", and under that, an item called "File's Owner." That represents the object that owns and manages the views in the XIB. Select that, and then display the Identity Inspector. There will be an entry at the top "Custom Class" where you can change the class that manages this view controller.
Before changing that, I suggest you create the source file for your view controller ("ViewController.swift", in your case.) Then when you change the class of the owning object, the XIB will create an instance of your custom class when that XIB is invoked.
The approach is quite similar for Storyboards, although it's a little more coherent.

How to load a View Controller SubClass with a nib without specifying the nib name as a string?

When you load a UIViewController Subclass programmatically, any nib associated with that ViewController will not be loaded if you named any of the files a different name than your subclass.
The only way to load the nib automatically, without passing a string name to the initializer, is to make sure your x.nib and class.swift has the same name as the SubClass.
Is there a way around this?
According to the documentation, you actually can load a nib based view controller without naming it exactly the same thing. Although matching names is the most common way to do this, there's a second case, which should work even with Swift.
From the documentation:
If you use a nib file to store your view controller's view, it is
recommended that you specify that nib file explicitly when
initializing your view controller.
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. Specifically, it looks (in order) for a nib file with
one of the following names:
If the view controller class name ends with the word ‘Controller’, as in MyViewController, it looks for a nib file whose name matches the
class name without the word ‘Controller’, as in MyView.nib.
It looks for a nib file whose name matches the name of the view controller class. For example, if the class name is MyViewController,
it looks for a MyViewController.nib file.
The nib will only load automatically if BOTH the nib and class-file are the SAME name as the class...

How can I create view controller that is defined in XIB?

Sorry for perhaps noob question, guys. I'm new to iOS development.
How can I create view controller that is defined in XIB ?
When you create new class inherited from UIViewController in Xcode via "New File" and mark with XIB checkbox it creates xib file that doesn't have viewController element. But rather it has placeholder which points to UIViewController which is defined in the code.
But I see that you can create controller itself in Interface Builder and specify customClass for it.
Unfortunately it doesn't work for me. I get loaded the "EmbeddedViewController" nib but the view outlet was not set error in run-time. But I believed view property must be set by resource loader automatically since everything is defined via XIB. It works that way for TableView and its cells for example.
Could you please provide example how to do it ?
I created sample project: https://github.com/cppexpert/SampleWithNib
The controller in question is EmbeddedViewController
Create one Xib per UIViewController
Each Xib have File's Owner object for you to set UIViewController class there. Click File's Owner and choose EmbeddedViewController on it's class
Then drag main UIView not UIViewController class to there, then hook up this view with file's owner as view. UIViewController just use to drag to StoryBoard base project.
https://github.com/lequysang/gitfiles02/blob/master/SampleWithNib-master.zip
Turned out these controls exist in IB for Storyboard projects.
When you create a view controller with xib via "new file", Xcode generates an UIView and connects it with view outlet automatically. Seems like you changed something after Xcode generated the xib file. In that case you need to connect a view to the view outlet manually.
If you create a new view in xib.set the file owner to your custom class.
Or if you simply want to create a view.
Then
NSArray* test1 = [[NSBundle mainBundle] loadNibNamed:#"View" owner:self options:nil];
self.myViewFromNib = [test1 objectAtIndex:0];
Where myViewFromNib is your view object and "View" is your nib name.

Resources