Passing data to the view controller that UINavigationController points to - ios

So heres my question. I am a silent stackoverflow skimmer and Im using xcode 4.5 storyboards for an application which starts with a view controller which asks for the username and password. My application checks data via a backend server and then if the login is correct it performs a segue which points to the uinavigationcontroller which forwards the screen to the main menu.... The uinavigationcontroller hasnt been tampered with and pushes the mainmenu automatically.
Login_screen -> UINavigationController -> Main_Menu
My question is how do i pass the NSString username from the login screen to the main menu screen.
I understand how to pass data from one screen to the next when the segue is pointing directly to it via the prepareforsegue method as well as performsegue. But in this case the login_screen segue points to the uinaviationcontroller which points to the main_menu controller
My assumption is that i will need to make a custom class which inherits UINavigationController and implement certain methods but since uinavigationcontroller isnt seen i dont think viewdidload or viewwillappear are the right methods.
Any help will be appreciated
I am a new user so i am not allowed to post images but i will fix that as soon as possible

You can use the topViewController property of the UINavigationController.
Cast the UINavigationController.topViewController object to Main_MenuViewController and set the data normally.
Hope this helps

in whatever case you need some container to persist the current selected/active object. I f for whatever reason you can't extend the UINavigationController (I'd wonder why), you can always have some property in AppDelegate you can assign and in your final Main_Menu controller read this property.
Smth like this:
AppDelegate* app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSObject* myThing = app.myObj
if(!myThing) {
app.myObj = ...
}

Related

Stacked UINavigationController

I'm new in iOS and I'm working with Storyboards.
I have an application with some views.
My rootViewController (1) is a UINavigationController that connects to other views. At one point in the application (2), I include a component (SWRevealViewController, Facebook Side Menu Style) that is an instance of UINavigationController, so I have two UINavigationControllers nested within each other. I want to remove or change the first UINavigationController by the new one (2), and just have only one. All views are accessed via custom segues.
Detailed Image Here
I think the solution is to change the rootViewController before loading the view (2), and set the second UINavigationController as the main of the application.
Detailed Image Here
I tried to solve it accessing by:
[UIApplication delegate].window.rootViewController = myController;
but I only have nil or a empty window.
I read many post that the solution could be in my AppDelegate in the method
- (void) applicationDidFinishLaunching: (UIApplication *) application I can't understand how to apply it to my structure, because that method is called when the application is launched.
I think that my workflow application is wrong.Any feedback or help is welcome!
Thanks in advance.
It's fine to change the root view controller from another controller, but your code is wrong. It should be:
[UIApplication sharedApplication].delegate.window.rootViewController = myController;
If you're doing this action from a controller whose view is currently on screen, you can do it this way instead:
self.view.window.rootViewController = myController;
This should work as long as myController has been properly instantiated.
You could possibly remove (1) or off load it into another view controller that is hidden and once the user goes back to a point where you want (1) back you can load it back in. This could be done in the - (void) applicationDidFinishLaunching: (UIApplication *) application.

How to handle click events in UISplitView nested controllers

I'm Monotouch for iOS development.
I've got a SplitView for iPad and the main view controller is UITabBar with UINavigation inside and UITableView nested in it. Thats a quite complicated controllers chain. And I need to handle row click event in TableView and return it back up to UISplitView to make an appropriate action on DetailView controller.
Is it a good design to define an event in each controller in the controllers chain and transit the event from the very end to the very begining calling the intermediate events?
I would recommend to keep things simple. Usually the splitViewController is a property of the AppDelegate (if not, you can just add one). So you can access the splitViewController from anywhere in your app by calling
[[[[UIApplication sharedApplication] delegate] splitViewController] anyMethodYouWantToCallOnTheSplitVC];
#Tobi was on the right track, you can get access your AppDelegate using var myApp = UIApplication.SharedApplication.Delegate as AppDelegate; and at that point either reference the public instance of your UISplitViewController or call a public method from myApp.

IOS 5 Opening a specific ViewController from the AppDelegate

I am really new to IOS so I apologize if this questions is not worded clearly. I have tried searching around but I have not found exactly what I am looking for.
basically in my AppDelegate applicationDidBecomeActive method, I am making a call to my webservice to make sure that the user is still a valid user, and to pull down some refrehsed data, or kick them back to the login page if they are no longer valid.
The part that I am having trouble with is the second part. How can I load and show and specific ViewController(in this case the loginViewController) when the user is found to be invalid? I want to let the normal viewController flow happen when they are valid, which is is doing fine, but I can not figure out how to launch a specific viewController when I need to from AppDelegate.
Any ideas?
I think I got it! I used this code in the AppDelegate to display the ViewController I needed.
UIViewController *loginController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
UINavigationController *loginNavController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"LoginNavController"];
UIViewController *currentVC = self.window.rootViewController;
_window.rootViewController = loginNavController;
[currentVC presentViewController:loginNavController animated:NO completion:nil];
For simplicity, lets say you have a one view app (not nav controller, not tab bar controller - the solution scales but easier to explain). When you get the appDelegate message that the app launched, then make a UIImageView the root view and show your launch image (user thinks you are still booting up). Try to log in, and do this in some other object (not a view controller). If you succeed, you make your desired view the rootView, and users sees it. If the login fails, then you makea login window the rootView. The key here is to have an object that is driving this and can interact with the appDelegate. You could also add this functionality to the appDelegate itself.

How to pass a managedObjectContext from the appDelegate to the first ViewController when their is a navigation controller between the two views

I've been beating my head against the keyboard for a better of 3 days now in researching and trying to figure out how i can solve the following problem.
I have a story board that looks like this:
Initial app launch arrow -> to a Navigation Controller -> to the Main View Controller.
My appDelegate is creating the managedObjectContext and it populates some entities with data (for testing purpose only atm, it will be removed once I'm ready to integrate with an outside source). This work fine. Now my problem is that I don't know how i can pass the MOC from the appDelegate to my first ViewController because the Navigation controller is in the way. My current code in the appDidFinish Method looks like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Pass the managed object context to the root view controller
MainMenuViewController *rootView = (MainMenuViewController *)self.window.rootViewController;
rootView.managedObjectContext = self.managedObjectContext;
//My actual Core data setup and adding data to it, it works I've tested it.
return YES;
}
Now my code works when I change where the app launch arrow in the storyboard to point to my mainMenuViewController, but than I do however lose my navigation bar in all my views. I also know how to pass the MOC from my mainMenu to another view via the - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)senderbut I just can't seem to figure out how to do the initial pass from the appDelegate to the MainViewController because of the darn navigation controller being in-between the two.
I've already searched numerous threads on this site (and others) and i've only found the solution for a "Tabbed application" and others want me to serialize the object, but for my purposes I can't do that. (only a few views will receive the MOC and other will be passes data that one view has created and altered to be tailored for specific purposes in the unique views)
Any help to this nub in iOS and Objective-C is greatly appreciated. Thank you in advance.
EDIT: THe error i get is "terminating app due to uncaught exception ... [UINavigationController setManagedObjectContext] unrecognized selector sent to instance...
If you create a new application from the "Master-Detail" app template in Xcode 4.3 (and 4.2 as well, I think), with the "Use Storyboard" and "Use Core Data" options checked, you'll find the following in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
MasterViewController *controller = (MasterViewController *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
This seems to be exactly what you're looking for. The key bit is that you can query a navigation controller for its view controllers.
If the NSManagedObjectContext was setup in AppDelegate, you don't pass it; rather, you create a reference to it:
AppDelegate *appDel = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = appDel.managedObjectContext;
The type of object you reference it from is irrelevant, as is any other kind of object between the receiving object and AppDelegate.
In addition to my first answer, which is essentially the same as the accepted answer—except that, with mine, you can use it with or without any template (and not just the split view template)—I'm providing an answer that even more directly answers your question, and that is how to pass a reference to your context manager object to the destination view controller subsequent to a segue.
This answer, like my first one (and unlike the accepted answer), assumes that you at least know where the managed object context is in your app, and that you have the basic skills necessary to create a reference to it (unlike the accepted answer, which assumes you can't use Find... in Xcode nor can you remember how to assign a value to a pointer, such as:
id moc = [reference to the managed object context object that you can find]
Since you seem to respond better to answers that involve a template, try the prepareForSegue method override provided in the UIViewController subclass in the Single Application View template. Inside, you will note a couple of comments left there by Apple.
In short, you will create a reference to the destination view controller like this:
SecondVC *vc2 = segue.destinationController;
Then, you set the value of the pointer reference to the managed object context variable in the destination view controller to the value of the point of reference to it wherever the instance was created:
vc2.mbo = AppDelegate.mbo;
I provided a really thorough example (with a video demonstration) of creating segues without storyboards (i.e., programmatically) at:
Set segue identifier programmatically
By the way, if you're having difficulty with understanding the use of the AppDelegate reference in my answer, I'll explain it:
Apple puts its Core Data managed object context reference in AppDelegate.h/.m whenever you create a new project using any Xcode template, and also check the Use Code Data checkbox during template setup. To use that reference throughout the app (i.e., within other .m files, and so you don't in advertently create multiple instances of it), you create global, application-wide reference to AppDelegate—which happens to be a delegate of UIApplication, which is a singleton, making AppDelegate a singleton, too—by merely adding this to every implementation file in which you intend to reference the managed object context:
import "AppDelegate.h"
define AppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Now, you access the managed object context object anywhere these two lines are added:
[AppDelegate.mbo...];

iOS storyboards instantiate viewController and IBAction

I may go mad very soon.
This is the reason:
- I started up with Single View Application project with storyboards. Then I set the view controller class name in the storyboard for my viewController.
- Next step I created one pointer for this viewController in AppDelegate method ...didFinishLaunchingWithOpt... and filled it up by calling [myStoryboards instantiate...]. It works pretty good because I can call method like [vc1 setMyName] which does smthng like self.myName = #"Johnny";
- But here it comes. When I create IBAction method joined with button, this method doesn't know anything about "Johhny". And this is because I'm in another instance. When I check the address of "self" it is another one...
WhyWhyWhy??? Please help, how can I use still the same object - the one instantiated in AppDelegate by storyboards and the one from storyboards in "interface builder".
Thank you.
Oh my. I think I really underestamated it...
When we were talking about getting pointer of other viewControllers from storyboard...
I have initialViewController got by calling rootViewContr... And another one connected with segue (modal) where is UITableView. A get data on rootViewController and I want to show them on the other one in the list (UITableView). So I call segue (performSegueWithIdentifier), the other controller is shown but the list is clear. Because the method I call is working with tableView variable which is null :/ Because, again, I'm in another object. That is because I call that method storyboard instantiate... How can I get exactly the same viewController which I'm working in storyboard with. It is quite confusing for me :/
I read something about prepareForSegue and getting the pointer by destinationViewController but that is not what exactly I want. I need the pointer before I call segue method and the viewController is shown...
Thank you.
If you've set up your initial view controller properly in the storyboard, you don't need to assign it to the windows rootViewController property in -applicationDidFinishLaunchingWithOptions: as this is done for you automatically. It sounds like you're creating a second instance. To access the original instance setup by the storyboard simply do this in -applicationDidFinishLaunchingWithOptions:
InitialViewController *viewController = (InitialViewController *)self.window.rootViewController;
viewController.myName = #"Johnny";

Resources