storyboard or rootViewcontroller, which goes first - ios

At the launching phrase of an App, which controller would it use as the rootviewcontroller for it's window (while they both exist)? the one declared in AppDelegate or the one used in Storyboard?
If nothing is declared in AppDelegate, would the App create a UIWindow for it's .window property by default and make the entry viewController in the designated storyboard it's rootViewController?

If nothing added in applicationDidLuanch: delegate Method for creating a new window, so your app create your UIWindow and make the root is the root in your storyboard file, but if you want to create custom starting point, add another storyboard or even a single .xib file as your staring point and let your appDelegate know your starting point.

Related

How does Xcode sets rootViewController implicitly via storyboard?

Xcode with the project file and Info.plist locates the main.storyboard and finds out the initial ViewController. But I was hoping to see some boiler plate code in AppDelegate for the ViewController.
AppDelegate looks blank: (No reference to ViewController)
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
...
#end
StoryBoard is xml:
Question
Does Xcode what magic code to refer storyboard xml and find the controller ?
After the compilation, main() brings up AppDelegate which should either have reference to ViewController directly or have a proxy storyboard object to get to the ViewController.
What am I missing ?
I think my book (which you already found) explains it fully. main calls UIApplicationMain() and it follows certain rules. If you have a main storyboard designated in your Info.plist — and you do — then:
UIApplication pulls the initial view controller instance (the one with the Entry Point arrow) out of the storyboard. That's the ViewController instance.
It also instantiates the UIApplication class.
It also instantiates the app delegate class (specified in the UIApplicationMain call), and assigns it to the UIApplication's delegate property.
It makes a window and assigns it to the app delegate's window property, then assigns that view controller to the window's rootViewController property.
Then it shows the window (and calls applicationDidFinishLaunching... on the app delegate`).
That completely explains the launch process.
A picture is worth a thousand words.. However, here's a short description: "It's in your project's settings/info.plist".
In the picture below "Main" is the name of my initial storyboard. Also, initial view controllers have a flag in the interface builder that says "Is Initial View Controller" to tell it that's the view controller you wish to run first.
P.S. Clicking on the images enlarges them :)
The short answer is that the dynamic nature of Objective-C allows UIApplicationMain() to bootstrap your application solely from the textual information stored in your application's info.plist file and your main NIB or main Storyboard. There's no need for the compiler to generate boilerplate code.
The longer answer:
UIApplicationMain does the following things to through the Objective-C runtime:
In all cases, UIApplicationMain() instantiates the NSPrincipalClass key in your plist, typically UIApplication but can be a custom subclass.
In an old-style NIB-less application, UIApplicationMain() will instantiate the AppDelegate class that was specified in main.m. It will wire the AppDelegate to UIApplication, and then hand off to the AppDelegate to create the app window, root view controller, etc.
In a NIB-based application, UIApplicationMain does not know the name of the AppDelegate. Instead, it loads your main NIB file NSMainNibFile, as specified in the plist. The NIB is responsible for instantiating your AppDelegate and wiring to UIApplication, along with creating your main window and root view controller.
In a Storyboard application, UIApplicationMain instantiates the NSPrincipalClass and the app delegate as specified in main.m, just like a NIB-less application. It then loads the main storyboard, which knows who the initial view controller is. It creates a window, instantiates the initial view controller, and assigns it as the root view controller for the window.
That's the reason behind it :-
and if you remove that mark You'll get a blank screen.

Execute Code in Launch Screen UPDATED

Execute Code in Launch Screen ORIGINAL
Now that the default LaunchScreen file in Xcode projects have been changed from .xib to .storyboard files (just like Main.storyboard), is it now possible to design the launch screen programmatically if you choose to?
Can you write custom code for the launch screen?
It is not possible to write any custom class/code for the launchscreen xib/storyboard files. We can only design using resource files.
Completely Agree with Arun Ammannaya. I ran a test to verify it and here is the result.
Yes, its possible to write ViewController for the launch screen,
1) Create viewController file, create Xib for the same.
2) In the RootViewController's (say HomeViewController or SignInViewController) ViewDidLoad(),
2a) Create object of SplashViewController.
2b) Add view of splashViewController to your HomeViewController.
let objSplashVC = yourCode to create object of SplashVC
self.view.addSubView(objSplashVC.view);
c) After 2 or 3 seconds or once your retrieve data on Web-Service call, you can remove that view, by calling hide() method of SplashViewController
hide(){
self.view.removeFromSuperView();
}
Note : You have to add background image on SplashViewController as same as launchImage. So transitions will go smoothly.

Adding a navigation controller to a tab bar application

I have two questions about this one. First, I have the navigation controller successfully put in the storyboard and is linked with the tabs and is working how I would want it to. Except for one thing. When I try to add a code such as this
[self.navigationController popToViewController:vc animated:YES]
I get an error Property 'navigationController' not found on object of type 'AppDelegate *'
Is this because I put it in the wrong place? Or becasue its a tabbar application and something aint right.
It sounds like you're trying to make a call to your navigation controller from your AppDelegate. Unless you've specifically setup your AppDelegate to work with your navigation controller (it'd need to be a subclass of UIViewController), you'll get an error because there is no Navigation Controller on your AppDelegate class (by default). Therefore, when you make that call - the navigation controller can't be found. Notice how your AppDelegate is a subclass of UIResponder, not UIViewController:
#interface AppDelegate : UIResponder <UIApplicationDelegate>
Instead, create and / or connect your navigation controller to a UIViewController subclass - then you can make calls like this from your subclass:
[self.navigationController popToViewController:vc animated:YES];
To create and setup a Navigation Controller, follow these steps (may vary if you aren't using storyboards).
Create a new UINavigationController Obj-C subclass. In the Xcode menu bar, select File > New, or press CMD+N. Name your class and set its superclass as UINavigationController:
Note that you don't absolutely need an entirely new class! You can use an existing class that is a subclass of UIViewController - as long as the navigationController property is available.
Add your navigation controller from the objects library in Xcode and set it up the way you need it.
Select the NavigationController in your Storyboard, then open the Utilities Panel, and select the Identity Inspector Tab. Set the Custom Class name to the name of your UIViewController or UINavigationController subclass:
From your class you'll be able to use the navigationController property, among hundreds of others relating to the View Controller. Remember that the AppDelegate is really a place for setting up your app and handling app events (ex. app closing, app backgrounding, app opening).

UIKit restoration not calling viewControllerWithRestoreIdentifierPath on all VC

Overview of my app
-Throughout I use a navigation controller, it lies in a corresponding XIB MainWindow.xib. It is set as the root vc in the app delegate.
-CategoriesVC is a table vc, it is the top VC in the root vc.
-BooksCategoryVC (all books in a category) is another table vc that is pushed after selecting something from CategoriesVC
-BookScrollVC.m is a scroll vc that displays the text after selecting a book.
Code description
1) In my app delegate I have set shouldSaveApplicationState and shouldRestoreApplicationState to return YES
2) CategoriesVC lies in the MainWindow XIB and I have set the restoration identifier in IB and in .m I have set the restorationClass to self and implemented the viewControllerWithRestoreIdentifierPath
3) BooksCategory has its own XIB and implemented the restoration protocol, pretty much same as
4) Same as 3) except the VC is instantiated in code. No XIB here.
Flow
Start the application. Navigate all the way to the last VC (BookScrollVC).
When pressing Home Button in the simulator:
encodeRestorableStateWithCoder is called in CategoriesVC and doesn't proceed to the other VCs. Shouldn't it go through all VC that have implemented the restoration protocol?
When restarting the app from Xcode, indeed only the viewControllerWithRestorationIdentifierPath in the CategoriesVC is called.
Please let me know if anything is unclear or you wish to see code
Solution
The app cannot restore if the restorationidentifier is not set. Altough I have set them in my custom initialisers it didn't seem to work. The solution was to set the restoration identifier on the next vc, before it was pushed.
I will have to dive into this and see if there's a better solution.

UITableViewController being initialised twice

I was trying to modally present a UINavigationController with a UITableViewController as it's root view but kept crashing the app when pressing the button to present the modal view.
- (IBAction)flipToDefaultsViewController:(id)sender
{
RootTableViewController *controller = [[RootTableViewController alloc] initWithNibName:#"RootTableViewController" bundle:nil];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:controller];
nc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:nc animated:YES];
}
The app crash with the message:
[RootTableViewController numberOfSectionsInTableView:]: message sent to deallocated instance 0x5677b5
When I loaded up Instruments to take a further look it was apparent that two instances of my UITableViewController were created, one with the owner of the UINavigationController and the other by UIKit. The UIKit created instance was the one that was deallocated and causing the crash.
When I changed the initialisation from initWithNibName:bundle: to init the UITableViewController loaded fine (my .xib file was the same name as the class).
My question is why would this happen?
Should you not initialise a UITableViewController this way when adding it to a UINavigationController? I've had a hunt around the documentation with no joy so far.
Using iOS 5 with ARC but target deployment is 4.0.
I haven't worked out why the object was being initialised twice, however I did review the steps that I used to create the .xib file and it looks like there is a problem with copying a view from a Storyboard to Interface Builder. In hindsight this makes sense, but as the view appears to copy without error and everything else seems to look okay it's easily done.
It would appear that similar problems were experienced by others with similar results.
By creating a completely clean subclass of UITableViewController with a nib file (⌘-N) and copying code from the initial class into the new one I'm able to use the initial code above to alloc/init my modal view.
BTW I was mistaken in my opening post about the nib file loading correctly when using init. It wasn't and in fact this behaviour doesn't happen for UITableViewController apparently where as other classes having a class name the same as the .xib file will attempt to load the .xib first.
If this is a button, than you should not initialize anything when the button is pressed. You should initialize beforehand and simply present the modalViewController when the button is pressed.
Is there any reason why the rootViewController and the navigation controller cannot be initialized in the appdelegate didFinishLaunchingWithOptions method?

Resources