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).
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
Xcode Image
As you can see in the image attached I have the root navigation controller called - Notifications and a UIViewController called NotificationsController.
So my Question is how can i pass a variable from NotificationsController back to Notifications using Protocol and Delegate, because in this case there is no segue but a default relationship between them.
Is my question correct or is there another way to do what i need.
Any help is really appreciated
To reference the navigation controller from the view controller (it is an optional so you need to handle that):
// self is a UIViewController
self.navigationController
To reference the view controller from the navigation controller:
// self is a UINavigationController
let index = // Index of the view controller. You may need to iterate over viewControllers to find this.
self.viewControllers[index]
You don't really need to set up a delegate. As keithbhunter pointed out in his answer, a view controller has a navigationController property that will point to the navigation controller that manages it.
I suggest you define a protocol for the messages you want to send to your navigation controller, and then have your custom subclass of UINavigationController conform to that protocol.
Within the view controllers that are on the navigation controller's stack you can fetch a pointer to your navigation controller and cast it to type UINavigationController<myNavControllerProtocol>.
(UINavigationController that conforms to myNavControllerProtocol. I'm working in Objective-C these days and don't remember the exact syntax for that.)
I am trying to deploy from scratch something like BasicMenu example.
Steps are already done:
ECSlidingViewController created in storyboard with proper User Defined Runtime Attributes and set as init view.
MenuViewontroller created with identifier: MenuView and unwind method
HomeScreenViewController created with identifier: HomeScreen and rooted by UINavigationController
Created sliding segue from first cell in MenuViewController.tableView to UINavigationController of HomeScreen
In HomeScreenViewController created UIBarButtonItem with action binded to Unwind method.
After starting app all looks like Ok, but when I am tapping Menu button in the NavBar nothing happens. Also unwind method of MenuViewController not called.
P.S. I figured out that MenuViewController is not instantiated at runtime. No idea why =(
P.P.S. I found the issue!!! It was very stupid mistake - i am not appointed class to ViewController in the Storyboard.
The issue was in appointment class to view controller in storyboard. It was by default UITableViewController instead MenuViewController.
I need to create a modal "flow" within my app. It is made of two "scenes", these are both UITableViewController subclasses.
The user will be able to push and pop between these two table views.
At any point they will be able to press "Done" (in a nav bar) and dismiss the entire modal view to go back to where they were.
This whole modal flow needs to be accessible from several places in the app. I don't really want to create multiple modal segues to this.
My question is, creating this in a storyboard, would you create a whole new storyboard for this flow (I don't like this).
Would you just create multiple modal segues?
Should I create this flow in the same storyboard file but as a separate entity accessible by the identifier?
Or something else?
Sounds like it would be easier to use a single storyboard, but not create multiple segues everywhere. You can programmatically present the view controller pretty easily:
MyViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
// set any properties on vc here, if necessary to pass it any data
[self.window.rootViewController presentModalViewController:vc animated:YES];
You could place all this code in a helper method to reuse this code more easily, maybe a class method like this:
#interface MyViewController ...
+ (void)presentNewViewControllerModally;
...
#end
Tapping the done button:
[self.window.rootViewController dismissModalViewControllerAnimated:YES];
Note that if there's a good chance you'll never see this modal view controller, you could place that view controller in a separate xib file instead of in the storyboard, and I think that could make things more efficient (storyboard remains more lightweight). In this case, just replace the instantiteViewControllerWithIdentifier message above with:
[[MyViewController alloc] initWithNibName:#"SomeNib" bundle:nil];
...and the rest of the code is the same. I've used this technique for a "login" view controller that would only occasionally need to be presented.
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.