Return storyboard current view controller identifier - ios

How can I find the identifier of the current view controller that is instantiated?
Example:
self.storyboard?.instantiateViewControllerWithIdentifier("ThisViewController") as! UIPageViewController
And use something like self.storyboard?.currentViewControllerIdentifier to return ThisViewController?

From the documentation for UIStoryboard:
This identifier is not a property of the view controller object itself and is used only by the storyboard file to locate the view controller.
So the short answer is you can't. The longer answer is that you could subclass UIViewController and add a property for the identifier and have that be assigned every time you load from the storyboard.

Related

What is the relationship between the view controller on the storyboard and view controller I define through code?

When I create a view controller in the Interface Builder, I associate it with my code version of the class through selecting the appropriate name from the Identity Inspector. Is the view controller from IB a subclass of the class I coded?
As far as I can tell the view controller in IB is not an instance because you still have to instantiate it:
if let vc = storyboard?.instantiateViewController(identifier: "Detail") as? DetailViewController {
// use vc
}
I don't think it's a property of the code version of the view controller, DetailViewController in the above example. It's being instantiated through storyboard, which in turn is from UIStoryBoard.
Think of the storyboard as a resource file. instantiateViewController just reads that file and creates a certain UIViewController subclass, by calling its init(coder:) initialiser. After that, it creates all the views found on the storyboard, and adds it into the VC's view. How does instantiateViewController know which UIViewController subclass to create? The subclass's name is actually stored in the storyboard, exactly when you type "DetailViewController" in the identity inspector!
The View Controller you see in IB is only as much of an instance as this JSON...
{
"username": "Sweeper",
"id": 5133585
}
is an instance of this struct:
struct User {
let username: String
let id: Int
}
It's not a subclass of DetailViewController either. It's just data in a resource file.
A storyboard is a collection of scenes / vcs related to each others by a segue if exists , when you create a vc you have the option to create it completely programmatically in terms of it's layout or create it's layout inside a storyboard and then assign the vc name in identity inspector so that you use it to create instance of that vc with instantiateViewController which is linked to the layout specified in storyboard there is no super-subclass relation. the code in vc acts as the series of the vc's life cycle . think of the sotyboard part as an easy way to add the layout components like label / button with constraints to the vc's view instead of creating them programmatically that is the main difference
A view controller in the Interface Builder (IB) is not a subclass of the class you define in your .swift file. The storyboard really just helps you visually define the layout and constraints of the subviews that a UIViewController controls.
Basically what your code snippet is doing is "find the storyboard object with 'Detail' as its identifier, make sure its companion class is of type DetailViewController, and then create an instance of DetailViewController with the layout and constraints that are defined in that storyboard object".

In iOS, does a segue instantiate the new-to-be-used view controller? Or is it already instantiated?

So for instance, let's say I have a regular subclass of UIViewController and I have connected a control object contained within this controller's view to a segue action that will let another view controller's view come into view...
Simple enough.
When I call the method called prepare(for:sender:) on the regular subclassed UIViewController, at this point, I'm concerned with the new to be used view controller whose view will pop on the screen.. Is this new view controller already instantiated somewhere?
I believe the answer is yes because inside the prepare(for:sender:) function, I set a reference for segue.destination (which is the destination view controller) and when I print that reference, it seems to be a place in memory already which tells me that the new view controller is already instantiated.
Can anyone confirm/deny that this new view controller (created from the storyboard) already has been instantiated, or put this in simpler terms?
Thanks
Apple's documentation says,
When the storyboard runtime detects a custom segue, it creates a new instance of your class, configures it with the view controller objects, asks the view controller source to prepare for the segue, and then performs the segue.
( https://developer.apple.com/reference/uikit/uistoryboardsegue )
So the destination UIViewController is instantiated by the segue just before sending prepareForSegue to the source UIViewController.
So to answer your questions directly, it is "yes" to both questions:
In iOS, does a segue instantiate the new-to-be-used view controller?
Yes, the segue does instantiate the destination view controller.
Or is it already instantiated?
Yes, by the time your prepareForSegue is called, it is already instantiated - immediately beforehand.
UPDATE: As #Jeffery_Thomas commented, this is trivially easy to demonstrate by adding an NSLog() line to your destination view controller's init.
Can anyone confirm/deny that this new view controller (created from the storyboard) already has been instantiated,
Yes. That is what it means to trigger a segue. A triggered segue's job is to instantiate the destination view controller, and prepare exists so that you can configure that instance.

Loading a Swift based UIViewController from Objective-C

I am attempting to load a view controller nib whose File's Owner is a Swift based UIViewController class. The view controller is very simple at this point--just a single label (lblResult) whose contents get set at runtime. When loading the view controller, I get the following error:
this class is not key value coding-compliant for the key lblResult
I know that this is usually because the File's Owner is not set in Interface Builder, however, in my case it IS set. I have verified that the IBOUtlet for lblResult is properly set and that the view property is also properly set. The only real difference here is that I am attempting to load the swift based view controller within an app written in Objective-C.
In my view controller class I am setting the UILabel property as follows:
#IBOutlet weak var lblResult: UILabel!
and setting its value as follows:
lblResult.text = "Time \(hour):\(minute):\(second)"
In my Obj-C calling class, I am instantiating the view controller as follows:
viewController = [[UIViewController alloc] initWithNibName:#"SwfViewController" bundle:nil];
The nib loads into view when no outlets are set, but when there are IBOutlets, i get the error. Any clues as to why this is happening? Thanks!
If your nib is a View and the owner is a View Controller, make sure you connect your view controller's view property to the nib view. If your nib is a view controller, instead of setting the File Owner just set the Custom Class of the view controller to SwfViewController.
Is this view controller present in your storyboard? If yes, you need to load the view controller by calling.
viewController = self.storyboard?.instantiateViewControllerWithIdentifier("SwfViewController") as SwfViewController
Make sure you set the identifier of the view controller in the storyboard to SwfViewController.
The storyboard should look something like this.

Downcast/Upcast a View Controller From Storyboard

If I have a storyboard that contains a view controller named "ABCViewController"
"A_ViewController" is a subclass of "ABCViewController"
is there a way to initiate the view controller "ABCViewController" from the storyboard as "A_ViewController" ?
Here is what I do. Hope it helps.
let abcController = storyboard.instantiateViewControllerWithIdentifier("ABCViewController") as ABCViewController
object_setClass(abcController, A_ViewController.self)
now you can cast abcController to specific child view controller if needed.
You can't do this with storyboard. instantiateViewControllerWithIdentifier will return instance of ABCViewController, you can cast it to superclass (i.e.UIViewController) but casting to subclass (A_ViewController) won't work. You can read why you can't do this here.
If you want to have two view controllers with same layout, but different classes you should use xib
I do not think it is possible to achieve what you are trying to do, reason being:
In Storyboard you give specify the concrete class name in IB for a particular UIViewCotnroller UI. This means when you you instantiate this UIViewController that specific class will be created.
In your case Base class is specified in IB and you are trying to downcast it a derived class which is bound to fail.
With a reference to the storyboard, you should be able to do a regular cast to a base type:
let myController = storyboard.instantiateViewControllerWithIdentifier("MyViewController") as UIViewController
Remember to set the identifier for the view controller in the storyboard too!
Not sure what you are asking, presuming one of the following :
1) You want to link the storyboard viewcontroller to the A_ViewController subclass of ABC_ViewController. You can simply do this by selecting Class from the identity inspector :
2) You already have the ViewController linked to ABCViewController from the storyboard IndentityInspector and you want to programatically fetch it as A_ViewController type (subclass). You cannot downcast (from the parent to the child), so you cannot do something like (presume that sbID1 is the StoryBoard ID corresponding to your view controller) :
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewControllerWithIdentifier("sbID1") as A_ViewController
The reason is that, generally speaking from an inheritance POV, you cannot pass a parent type as a child type (only the other way around). You can downcast from Parent to Child only when you know that you have initially instantiated the object as a Child.
I have tried different ways but not able to solve it. I used following way to tackle it :
In storyboard, create copy of VC with child 2
Bind VC identifier to storyboard
Implement all IBOutlet and action in Base only
Instantiate Child 1 and child 2 from any class as required.
Benefits:
This way we can keep the sam UI for 2 different VC.
we can implement all UI related functionality in Base
We can reuse common code use BaseVC
We can implement logic in respective VC i.e. child 1 and child 2

Segue to a subclass of some view controller

I'm using a storyboard. Let's say I have a view controller that's named MYviewController.
In - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender; I would like to substitute the view controller that I'm segueing to, by one of its child, for example: MYviewControllerChild1 OR MYviewControllerChild2. The child that's segued to depends on the sender parameter.
These view controllers have the same scene (in the storyboard). Only their behaviour is slightly different.
I have a tableView that shows the user the settings of the application. When he clicks a cell, it segues to a viewController where he can modify the value of some setting. Some of theses are alphanumeric, others are numeric. Depending on which cell is clicked, I'd like the input viewController to format the value accordingly (if it's a decimal value I'll use a NSNumberFormatter for example).
Is that possible?
As mentioned in comments to your OP, I believe you should handle this kind of scenario in one viewcontroller.
However, if you insist on using separate controllers, maybe because you think the functionality will be expanded later down the line and therefore add more diversity, you need to handle this by creating multiple storyboard scenes - one for each child controller.
The destination view controller in prepareForSegue is imposed by the viewcontroller at the end of the segue in the storyboard. I don't think there is any way to override that.
As described, your problem isn't really a good candidate for a storyboard. If you use a storyboard you will have to create and sync multiple scenes. Several possible solutions::
Create multiple storyboard scenes and invoke them manually via performSegueWithIdentifier.
Use a nib file instead of a storyboard for this scene. You can use a single nib file since the view controller is created outside the storyboard with [[VCClass alloc] initWithNibFile: bundle: You can create the appropriate view controller class and pass the same nib file to all instances.
Use a single storyboard scene and view controller and pass in typing information in your prepareForSegue.

Resources