iOS & Swift: ViewController class is defined, but when is it created as an object? - swift

Learning Swift as my first new language in many years, I've come across something I'm curious about using Xcode and creating a new iOS project using the single view template.
In the default ViewController.swift file, UIkit is imported, and then the class ViewController is defined, inheriting from UIViewController. But I can't seem to find out where or how this class is ever created or initialized as an object.
Default ViewController.swift example
If I define my own class, or even want to create another view controller, I must first initialize it as an object somewhere in order to use it. So where is this default ViewController getting made?
Thanks for any help you can offer for me to try to conceptualize this!

Open your "Main.storyboard" file. Make sure View Controller is selected on the left sidebar:
Then on the right sidebar you can see that your ViewController class is in the class field:
So, when your app is loaded, the default storyboard is loaded, and that storyboard is responsible for creating an instance of the ViewController class and set it up for you. To test this out, you could create a new class, say ViewController2 and make it inherit from UIViewController. ViewController2 would then be available in the right sidebar:
And then your ViewController2 code will be used instead of ViewController.

You have changed the location of the ViewControllerQuestion.app file

I believe that the UIApplicationDelegate takes care of the creation of the initial view controller. You still can manually create view controllers as you mentioned and segue to them.
Normally you can create a view controller in a storyboard and use the Interface Builder to set up a segue to that view controller.
I hope this answers your question.

Related

Is it okay to define a custom view using Storyboard / NSViewController instead of XIB file

I always find it a little bit annoying (for lack of a better word) to define a custom NSView in a XIB file.
I have switched to using a custom Storyboard (one per class) and a corresponding NSViewController. When adding the view to my hierarchy I am simply using code that looks like this:
let viewController: CustomViewController = // Use my custom extensions to instantiate the NSViewController subclass.
self.view.addSubview(viewController.view)
Are there any drawbacks? Is it okay to use this approach or could there be any downsides (maybe a NSViewController instance receives additional events or is somehow added to another hierarchy by default).
As a general rule, a view controller in a Storyboard is backed by code in its controller class.
.instantiateViewController(...) is then used to load a view controller from a Storyboard and:
push it
present it
add it as a child view controller, most often followed by adding its view to the current hierarchy
If you do have code backing that view controller, and you haven't added it as a child or assigned it to a class var/property, then the controller code will no longer exist as soon as viewController goes out of scope. If you've connected any UI elements to that controller class, or you need to call any funcs in that class, you'll run into problems.
However, assuming you do not have any code associated with that VC, then it's really functionally equivalent to designing the view in a XIB and instantiating it with from the resulting Nib.

How to set a view's outlets' values from within another class

In xcode, If we have a view controller that has some subviews' (eg: label) outlets, and we want to change its text from the AppDelegate.swift class whenever an app is becoming active after suspended, How can this be done? I have tried making an instance of this view controller class from the AppDelegate class, but that didn't work because it made another view instance instead of the view itself, and we can't set the outlet as static. I have also thought of making a static ViewController property observer, but since it is static I still can't set the outlet from inside it. So, how can we do such a thing?
The best way to achieve what you want - is notifications. In your view controller add observer which will change your label's text or whatever. From AppDelegate method post notification. If you need an example, I can help you.
If we have a view controller that has some subviews' (eg: label) outlets, and we want to change its text from the AppDelegate.swift class whenever an app is becoming active after suspended, How can this be done?
Don't. Never speak directly to another class's outlets. Give that class a method that you can call where that class will respond to the calling of that method by speaking to its own outlet.
I have tried making an instance of this view controller class from the AppDelegate class, but that didn't work because it made another view instance
Correct. You need to get a reference to the existing instance of the other class. To do that, you need to know your own view controller hierarchy / structure or else provide one class with a delegate / reference to the other class at the time of creation.

Replace ViewController in Storyboard while keeping Segues

I have a Storyboard where I have for example a UITableViewController with some incoming and outgoing Segues. Let's say I want to make this UITableViewController a UIViewController. Currently I would delete the UITableViewController, drag a UIViewController on my Storyboard and recreate all the Segues.
Alternatively, I would split my Storyboard using Xcodes Storyboard refactoring so that I at least only have to recreate all the outgoing Segues. But this cannot be done or at least is not practical in some cases where I want my ViewControllers to be in the same storyboard because they belong together.
As you know, this is cumbersome and I think it is prone to error.
So my question is: Can I replace a ViewController in my Storyboard without losing the incoming and outgoing Segues?
As I know it isn't possible with IB. It's only possible to exchange the controller class name in the settings. But a UITableViewController has additional settings that wan't disappear/appear by a simple rename.
My suggestion is to create the new view controller, link the seques one by one and than remove the no longer linked UITableViewController.
(That's one of the several reasons I do not use storyboards anymore. Instead I try to implement screens independent of each other, so I can change flow and/or replace single screens more easily.)
Unfortunately Xcode does not have this, at least as of 9.2. The solution is to edit the storyboard file in an editor, but it's really not so bad.
Get the Object ID of the controller you want to replace, and the one that will replace it. It's in the Identity Inspector, Document section, labeled Object ID.
Make sure you save the Storyboard before editing it outside of Xcode.
Each of the segues looks like this in the storyboard file:
<segue destination="S3O-z0-PFf" kind="showDetail" identifier="abcde2" id="x0q-y6-ZkJ"/>
Replace the destination ID with the new view controller's Object ID:
<segue destination="b5A-4F-zOe" kind="showDetail" identifier="abcde2" id="x0q-y6-ZkJ"/>
Save the file, and Xcode will reload it automatically. The segues will point to the new controller.

iOS5 Second View Controller

I'm trying to create a second view controller and link it to a new set of .m & .h files then alter the text of a label on that view controller under the viewDidLoad but am having some issues.
Here's what I am doing so far.
I'm starting with a blank new single page, from the MainStoryboard, I add a new VC and add buttons so I can navigate between the pages. This works fine.
Next I create a new Objective-C Class, "SecondViewController" and choose subclass UIViewController.
Now back on the Storyboard I select the other ViewController and try to pick the new SecondViewController as a Custom Class but it doesn't show up in the list of available classes.
Now, if in step 2 I choose the UIView subclass I can assign it to the ViewController in step 3 but the viewDidLoad options are not available so I am not sure how to program changes to the VC.
What am I missing here?
I am able to use the UIView and use the following to make the change I am asking about. I am not sure if this is the correct way to do this.
- (void)drawRect:(CGRect)rect
{
myLabel.text = #"change2";
}
EDIT ----
Okay, I've figured it out. I was clicking on the VC's View (background) in the Storyboard and not the actual ViewController! Now it works the way I thought it should. I suppose if I had looked at the View Controller Scene I would have noticed what I was doing incorrectly.
Now, if in step 2 I choose the UIView subclass I can assign it to the
ViewController in step 3 but the viewDidLoad options are not available
so I am not sure how to program changes to the VC.
The class of your ViewController (or similar one) from interface builder and another class in your code must extend the same class

How to change the default View Controller that is loaded when app launches?

I have an application, say 'MyApp', which by default loads the view controller 'MyAppViewController' whenever the application launches. Later, I added a new view controller 'NewViewControler' to the project.
I now want the 'NewViewController' to be my default view controller which loads when the app launches.
Please let me know what changes I need to make in my project to achieve this.
Its easy, just:
Open your Storyboard
Click on the View Controller corresponding to the view that you want to be the initial view
Open the Attributes Inspector
Select the "Is Initial View Controller" check box in the View Controller section
Open MainWindow.xib and replace MyAppViewController with NewViewController.
In your app delegate class, replace the property for MyAppViewController with one for NewViewController. Connect NewViewController to its new outlet in Interface Builder.
In application:didFinishLaunchingWithOptions: add NewViewController's view to the window instead of MyAppViewController's view.
Most likely your main NIB file is still set to "MainWindow", check your *-Info.plist file.
If that's the case you can open the MainWindow.xib in Interface Builder. You should see a View Controller item. Bring up the inspector window and change the Class Identity to point to your new class. That should take care of instantiating your class.
As this feels like a "newbie" question (please pardon me if I'm mistaken) I would also highly recommend the following article:
iPhone Programming Fundamentals: Understanding View Controllers
Helped me understand the whole ViewController thing and the IB interaction..
As for me with xcode 4.3.3, all I had to do was simply replace all references of 'MyAppViewController' with 'NewViewController' in the AppDelegate h and m files.
Perhaps all the other steps have been taken out in the newer versions of xcode.
Hope this helps.