Loading a Swift based UIViewController from Objective-C - ios

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.

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".

ViewController's subview's IBOutlets nil in viewDidLoad from Storyboard

I have a UIViewController that gets instantiated from a Storyboard.
In this view controller lays a MyView that is actually just a UIView from a Xib file.
In the view controller, I set my view as being a class of MyView and link it to an IBOutlet in my view controller class.
MyView contains a UILabel.
When in the view controller, in viewDidLoad I try to set myView.myLabel.text = "test" I get a fatal error: unexpectedly found nil while unwrapping an Optional value, myLabel is nil.
Can't figure out what's wrong.
Even in awakeFromNib() and in required init?(coder) my outlet is nil.
Any idea why and how to fix it?
Double check to make sure your link between storyboard and code is ok. I had this once when broke the connection and all I had to do was reconnect it.
See if you are using CustomViewClass in xib i would like to tell you first declare property as #IBOutlet var viewObject: CustomViewClass! in your Vc.swift & then give outlet opposite in storyboard & then inner subviews outlet declare in the CustomViewClass.swift
Now you are feel free to access in the your Vc.swift that innersubviews outlets of your CustomViewClass like
viewObject.myLabel.text = "test"
Don't forget to give Custom Class from identity inspector for file's owner Vc & your view CustomViewClass
Still if you have any doubt feel free to ask in comment.

Return storyboard current view controller identifier

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.

Multiple View Controllers and one view nib

I want to achieve the following:
I have a nib which has a View Controller which is responsible for that view.
I want to write classes which inherit from this view controller and therefore share the same nib file as the base view controller but add additional specific code. I could just build a whole lot of functionality into the base view controller but then it gets messy; I really want to be able to have the same base structure with one nib and then have subclasses which add additional features.
The trouble I am having is in instantiating (in code) the subclasses using the base class's view.
I have tried [NSBundle nibWithNibName:...] and [[vc alloc] initWithNib:...] - they all give errors.
Do I set the file's owner to the base class? Do I set the view's custom view controller for the base class? How do I achieve this?
Thanks
To set up outlets from the view controller to the view or subviews, you must set the File's Owner in the nib to the view controller's class.
The actual view controller can be a subclass of the class declared as the File's Owner in the nib. But then the outlets must still be in the superclass, or you won't be able to load using the other subclass.
So for example let me call the view controller SuperVC, Sub1VC, and Sub2VC. Then:
Define all needed outlets in SuperVC
Declare File's Owner in the nib as a SuperVC
Draw all outlet connections in the nib, including view of course
Now say:
Sub1VC* vc = [[Sub1VC alloc] initWithNibName:#"nibname" bundle:nil];
Or:
Sub2VC* vc = [[Sub2VC alloc] initWithNibName:#"nibname" bundle:nil];
They will both work.
It sounds to me like you need to set the view outlet.
This is a seriously common mistake. Just control + drag from the File's Owner (the base view controller), to the top level view, and set the outlet of view.

Table View Controller code not getting invoked

I've got an app with a Web View and a Table View. The Web View works fine, but the Table View does not seem to be invoking the TableViewController.h code when displaying. I think I missed a linking step somewhere, but I can't seem to figure it out.
To clarify, I originally set up the project as a single view application but later added a Navigation controller and the Table View manually.
After I manually added the Table View to the storyboard, I created TableViewController.h and TableViewController.m, but I can't figure out how to link the code to the Table View in the story board.
Can someone explain what I'm missing?
Set the class of the controller you're using in the storyboard to be TableViewController
Two scenarios:
First, if you added a tableview to a standard UIViewController (i.e. you dragged a table view to your blank, standard view controller in Interface Builder and the .h for your view controller specifies that it is a subclass of UIViewController), then you have to specify the "data source" and "delegate" properties of your table view manually. Thus, you should make sure to configure the "data source" and "delegate" for your tableview to reference your view controller. You can do this in either Interface Builder (by selecting the tableview, going to the "Connections Inspector" in the far right panel, and then make sure you've specified the outlets for data source and delegate):
Or set dataSource and delegate properties in your UIViewController subclass viewDidLoad code:
self.tableView.dataSource = self;
self.tableView.delegate = self;
In this scenario, you also want to ensure that you created a IBOutlet for your tableview, too.
Alternatively, if you used a UITableViewController (i.e. you removed the blank view controller and added your own table view controller into your storyboard in Interface Builder and have made sure that your view controller is a subclass of UITableViewController, not UIViewController), see Moxy's answer.

Resources