UIViewController inside XIB? - ios

Currently I'm struggling with creating a subclass of UIViewController or UINavigationController with XIB file as a view.
When I create everything from the Xcode's menu (New File -> Class -> With Nib... etc.) I get a XIB but only with a plain UIView but I want UIViewController instead.
I read somewhere that XIBs are only for a views and you have to handle controller in code, is it true? Because as you can read here it's possible to insert Navigation Controller component into XIB. But I have one problem with the code from this tutorial - I get empty view with empty UINavigationBar. When I do the same with regular View Controller I get info abut this controller being used more than once...
I'm not trying to force Interface Builder to do something unusual but I want to know if this is possible (it would be easier and nicer to modify view controller component insted of a content view)? And if it is, how to achieve this?

I have just checked to confirm whether it is possible and to my surprise it is! You can have UIViewControllers inside Xibs
The test was done in XCode 10.1, Swift 4.2.
I have never used it before, but i thought since it gives you the option from the item library to pick view controllers, it has to be possible. I have added one to my xib, and just like in the storyboards, i have linked it with class, set IBOutlets and IBActions and it all worked perfectly fine.
The key thing is to instantiate it like this:
// Method inside the `UIViewController` you want to present our view controller from xib
// The xib file is `XibViewController.xib` and it has only one item inside - `UIViewController` with custom class set to `XibViewController`
guard let xibViewController = UINib(nibName: "XibViewController", bundle: nil).instantiate(withOwner: self, options: nil).first as? XibViewController else { return }
present(xibViewController, animated: true)
here you can find my test project: https://github.com/stoqn4opm/XibViewController

An XIB file is used for building content that is viewable on a screen. A UIViewController is not viewable. It instead owns a view (which is viewable) created from an XIB or from code.
I think from what you are trying to do is use a storyboard which lets you visually layout your UIViewControllers to define there segue from each other (in your case in a Navigation Controller) which means show the next UIViewControllers view and put it in the UIViewController hierarchy.

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

Can you define a Segue in the storyboard to self?

I have an app that represents a folder structure. I have a UITableViewController for the folders and files listing, and a UIViewController for the Documents.
I want to be able to recursively navigate through the folder structure, so I want to reuse the Folder UITableView multiple times while I let the user drill down a folder structure.
Is there a way to draw a segue from the UITableViewController to self so when I select a folder I present another instance of the view, but with the content of the subfolder?
I did this in previous versions of Xcode, but I cannot figure this out on Xcode 9.
You can use Storyboard Reference and Storyboard ID of ViewController in Interface Builder
Screenshot
Yes you can do it. Add a hidden button in view controller and drag & drop segue self view controller.
I've never created a segue link to the same view controller, but based on Halil's answer above, it sounds like it's possible.
Rather than messing with hidden buttons, though, why don't you give your scene a storyboard identifier, and then instantiate and push/present your view controller through code? You could put your logic in the table view's tableView(_:didSelectRowAt:) method.

How UIViewController interact with Storyboard under the hood

I'm new to iOS development and this could be a stupid question for some experienced guys...
When I create a new iOS project in Xcode, I get a ViewController class and a storyboard which sets its Custom Class to this ViewController. It looks like there is a "Storyboard" class holding an instance of ViewController, however, I cannot find where this "Storyboard" class is defined.
Even though I know how to create multiple subclasses of UIViewController to handle different views interaction following some tutorials, I still find it uncomfortable to associate these subclasses to the storyboard by selecting them in the storyboard panel. I would rather see something like a "Storyboard" class holding an array of UIViewController.
So my question is, how these UIViewController interact with the Storyboard under the hood?
Thanks
Roughly, it happens as follows:
App launches.
App loads storryboard.
Depending on app's navigation structure, app instantiates each view controller inside the storyboard as needed.
The storyboard contains detailed information on:
Which custom subclass of UIViewController, UINavigtionController, etc. to use for instantiating each view controller in the storyboard.
How to map (connect) each if its view controllers' subviews to the corresponding custom classes' outlets and actions.
But seriously, read Apple's docs. It's all there.
UIViewController has a property named storyboard which refers to the storyboard file associated with the viewcontroller subclass.
Also the view controller code are interecting with the storyboard with connections symboled with #IBOutlet and #IBAction.

Create View Programmatically in Objective-C Xcode 5

How should I go about creating a View for the storyboard programmatically? I want to access the labels from the first ViewController object made(automatically to call the IBAction methods of VC). I know that this first object of VC is the one linked to the view in the storyboard(?) and I need to change a label form another file, besides VC. I'm pretty sure the only way to do so would be to access the VC object that is linked to the view, or create one and not go with the default one that is created. If not, how would I go about accessing the labels of the view from another file?
You don't create storyboard objects programmatically. A storyboard is very basically an XML file Xcode uses to call different view controllers. The biggest advantage of using storyboards over NIBs is you can layout transitions or segues, and the advantage of NIBs or storyboards over initiating view controllers by code is obviously the visual interface. So your question doesn't really make sense.
If you want to reference a particular view controller's label from your storyboard you need to create a pointer to that view controller first, but changing it programmatically doesn't make sense because that's what storyboard is for.
That said you may just need to go look for your class name in your view controller's Identity Inspector in storyboard and then edit your label programmatically through an IBOutlet property.

Reuse childs from custom UIVIewController using storyboard

I have a storyboard with a navigation controller that leads to an UIVIewController that I want to reuse. That UIVIewController has a ParentUIViewController that has all the basic functionalities for all the UIVIewControllers that I am reusing.
Currently I am copying and pasting (meh) and then I change the class of the UIViewController to the ChildUIVIewController that I want to use (ChildUIViewController extends ParentUIViewController).
But this sounds like a bad solution. Everytime I want to change the ParentViewController visually I need to update, manually, all other ChildViewControllers.
I have tried to create a xib for the ParentViewController but the xib isn't loaded because I need a xib with the name of the ChildViewController. I have created it and then said the class is the ParentViewController but it crashes in the segue.
EDIT
I have created an example of the status of my problem
https://github.com/tiagoalmeida/storyboardexample
Note that the ParentViewController has a set of logic way more complicated that is not illustrated there. Also note that I am also using a TableView. I hope that this can illustrate the problem.
Keep the logic on the parentViewController and the UI Part on the child UIViewControllers. If you need to create a new UIViewController, you will create a child that will have a corresponding XIB (or get rid of XIBs and create the interface by hand).
Have you considered looping back into the same UIViewController via a "phantom button"?
Have a look at this: UIStoryboard Power Drill, Batteries included
Essentially you can drag a Bar Button Item into the little black bar under the View Controller in Storyboard (the 1 with View Controller, First Responder, and Exit icons; sorry, I don't recall what this is called exactly), then you can control+drag from that button back into the UIViewController for a Push segue. This should create a loop segue in your Storyboard. All you need to do next is give that segue an identifier, programmatically call it from your code using [self performSegueWithIdentifier:], then implement -(void)prepareForSegue: and use [segue destinationViewController] to conditionally set the title and perhaps some flags so you can identify when to use different kinds of fetches (or other code variations) in the same Class code.

Resources