I have a question regarding window and viewcontroller in iOS. I just have a look at the app delegate of iOS project that I am working on today and found that it is required to have...
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
in my app.
Here are the questions:
Does this means that navigationController is the root view controller of my app? NavigationController is a subclass of UIViewController, but its task is only for providing navigation function at the navigation bar, correct?
What is self.window? I think I understand the concept of 'view' and 'viewController' but I do not quite understand what a 'window' is... An iPhone has one screen, but MacPro could have 2 monitors; Are these windows in terms of iOS and OS X?
Possibly. self.window.rootViewController will return the root view controller of the window, I presume, in this case, from the storyboard. The fact that this line casts the object returned to a navigation controller doesn't make it one -- it will be whatever it is in the storyboard (the controller with that left arrow that's not connected to anything else). Assuming that the cast is correct, this allows you to write things like navigationController.topViewController and not have the compiler complain about it. As for the navigation controller's function, it does provide the function for the navigation bar, but it also shows the view of its content controllers, with its topViewController's view being the one that you will see at start up.
A window in iOS, is a UIWindow, which is a subclass of UIView, so it's not the same as a window in OS X. Look at the Overview section of the UIWindow Class Reference for a discussion of what it does.
Related
I recently changed my app structure to include a UINavigationController as base for my hierarchy and I had its root viewController implement the UINavigationControllerDelegate protocol in order to implement custom segues.
My viewController implements navigationController:animationControllerForOperation:fromViewController:toViewController:.
My problem is two-fold:
The navigationController.delegate methods are not being called.
The navigationBar is not called in the views being pushed via storyboardSegues of type show.
The prepareForSegue:sender: function is being called.
This is my UI:
Turns out that UIStoryboardSegues I added before I added the UINavigationController to my hierarchy are still interpreted as modal segues. Probably this is set during creation.
The problem was solved by deleting and re-adding the segues in question, with the relevant information (identifier, class...) transferred to the new instance.
If you have the same problem, when you set Top Par to inferred in your segued viewController you will see no navigationBar showing.
After replacing the segues the Top Bar showed again as normal.
Edit:
I posted the question together with this answer, since there was no post on SO covering this issue. self-answer
I am developing an application with iOS 9 based SDK , this is my first time I am working with Storyboards , I have 20 view controllers, each scene has Next / Previous buttons to go back and forward . I have a huge problem with going forward !. If I move from scene 1 to for example to scene 15 I received memory warning and then application crashes . I have searched and it seems there is method called unwind segue but it seems this is for going back ! it's something like dissMiss method .
I connect each scene with line in Interface Builder :
Here is segue's setting :
I would be grateful if you help me out .
EDITED :
I tried to present a view controller programmatically but result was the same ! .
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
WhatIsDino *vc = (WhatIsDino*)[mainStoryboard instantiateViewControllerWithIdentifier:#"WID"];
[self presentViewController:vc animated:YES completion:nil];
Seems like it's a problem of wrong approach, and not the storyboard.
Let me guess, since before storyboard you used to change your app's rootViewController to the next/previous screen once you tap on the arrow button. So previous screen are released and deallocated from memory once you set a new rootViewController.
And now you're presenting every next view controller modally, which involved creating new UIWindow and loads all the hierarchy of you screen and keeps previous underneath the new one so it holds the memory and you're getting out of memory crash.
Well, you can do rootViewController approach with a storyboard too since it's just another way to manage your screens while development. Storyboard offers additional features like segues, static table view cells, general tint color and so on. [UIStoryboard -instantiateViewControllerWithIdentifier:] is the method you might find interesting.
But I'd rather recommend you to check out the UIPageViewController, it's like a container for the screens. Unfortunately, it cannot have the segues to your scenes (because of the special way segues work) so you have to use -instantiateViewControllerWithIdentifier: method anyway. You can treat inner view controllers of UIPageViewController as you do with rootViewController before.
You can also navigate without segue and Its easy way I think.
If you want to navigate from Class1 to Class 2 then follow these steps.
1) In Class 1, Import Class2.
2) In your button Action, Write this code.
Class2 *next = [self.storyboard instantiateViewControllerWithIdentifier:#"Class2 Identifier name"];
[self.navigationController pushViewController:next animated:YES];
Do not forget to give Identifier name in story board that is "Storyboard ID" in Attribute inspector of particular class.
No need to add Segue,Your storyboard would look clean.
The problem is that you are adding view controller after view controller with modal presentation. That causes each view controller to be added on top of the previous one, and all of them accumulate, using more and more memory.
Using a navigation controller and a push also piles the view controllers on top of each other.
You will have this problem if you use storyboards, nibs, or create the view controllers manually.
If you have a design where the user can move through a large series of view controllers then you probably want to dismiss the previous one before pushing/presenting a new one.
You can probably dismiss the previous view controller without animation and then present the new view controller each time you want to display a new one and avoid the memory issue. i'd have to experiment with it to get the effect I was after, but that's what I would suggest.
I perform some data loading tasks from an Ojective§C class and once everything is loaded, I simply wants to display a Viewcontroller subclass prepared in a storyboard.
So when everything is ok, the following method is called:
- (void)loadingNextView
{
CABBndGSite *mySite = [CABBndGSite alloc];
CABBndGSelectLanguageViewController *vc = [[mySite myRootViewController].storyboard instantiateViewControllerWithIdentifier:#"SelectLanguageViewController"];
[[mySite myRootViewController] presentViewController:vc animated:YES completion:nil];
}
So I verified that myRootViewController is not nil. It's a UINavigationController class.
vc is not nil so it found my view in the storyboard.
Anyway, the presentViewcontroller message seems to doing what expected.
Certainly a stupid mistake but my poor iOS programming knowledge lets me in the fog!
I use this code from ViewController subclasses with success and as here I get a valid ViewController pointer, I don't understand why it doesn't work.
I also tried to implement the AppDelegate method explained here How to launch a ViewController from a Non ViewController class? but I get a nil navigation pointer. Maybe something not well connected in my application
May I have some explanation?
Kind regards,
UINavigationController maintains a stack of view controllers. You can access this stack through the viewControllers property. To present your view controller, you can:
(a) have the navigation controller push the new view controller on to
the stack (pushViewController:animated:);
(b) have the top view controller in the view controller stack present
the new view controller modally (presentViewController:animated:completion:), or;
(c) add the new view controller to the view controller stack array
manually by assigning a new viewControllers array to the navigation
controller's viewControllers property (setViewControllers:).
This used to be pretty straightforward in the good ol' xib days. I'm getting into custom transitions in iOS 7. The root view controller for the my app is a UINavigationController. To get custom transitions to work, I need to set the delegate on my main UINavigationController.
I'd like to do this as soon as possible after load time. I tried doing it in application:didFinishLaunchingWithOptions:, but self.window.rootViewController is returning nil at that point.
So I guess my question is: when is the earliest I can set the delegate?
I suppose I can do it in viewDidLoad of my main view controller (the Navigation controller's root view controller), but that seems like the wrong place design-wise.
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).