I am working in xcode on an ipod app in objective C, and I have a field (navigationController) in one of my classes (rootViewController). How do I reference the instantiated rootViewController's navigationController from another class? For example, how would I do this if I want to reference the navigationController from the FirstViewController.m class?
I seem to only be able to find references for this to reference the application delegate.
If I want to reference the application delegate with FirstViewController, I just say:
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.navigationController pushViewController:childController animated:YES];
how do I do this for the rootViewController class instead of MyAppDelegate?
Based on the question you are asking, it seems that you want to call methods on the UINavigationController that is higher up in the stack. All UIViewControllers already have a property of navigationController which is the UINavigationController that is an ancestor to this ViewController on the stack.
So if you had a RootViewController, called root, that at some point did this
FirstViewController * first = [[FirstViewController alloc] initWithNibName:#"FirstView" bundle:nil];
[self.navigationController pushViewController:first animated:YES];
[first release];
Then first.navigationController == root.navigationController
So inside of first calling
[self navigationController]
will give you the same navigationController that first was pushed onto in the first place.
One object needs a reference to the other. There are many ways to make this happen. For example:
Have the same object create both and, since it knows them both, tell them about each other
Create them in the same nib and hook them up with normal connections
Have the owner of the nib one of the objects is in know about the other
Essentially, this is just a matter of designing your application properly so that the objects can be told about each other. There is no one magic thing you do.
Related
I am setting up an iPad app that uses a SplitViewController. In my app delegate I have the following in didFinishLaunchingWithOptions:
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *leftNavController = [splitViewController.viewControllers objectAtIndex:0];
LeftViewController *leftViewController = (LeftViewController*)[leftNavController topViewController];
DetailViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
NSLog(#"Detail View Ctrl >> %#", [detailViewController class]);
When I run the app, the NSLog statement returns "UINavigationController" when DetailViewController is actually a subclass of UIViewController. However, in XCode, code completion shows all the methods that are implemented in the DetailViewController subclass. Any ideas? Thanks!
I think your DetailViewController is actually embedded inside a UINavigationController, and your fourth line is in error. Take a look instead at the topViewController for the second view controller inside your split view controller, much like you do for the LeftViewController.
The reason Xcode is continuing to suggest completion for DetailViewController methods is because you've given it that type. Code completion doesn't rely on runtime behavior (how could it?) – instead, it relies on static analysis of the code that you type. If you tell Xcode that something is a DetailViewController, it'll believe you and autocomplete based on that information.
I have one UIView that I want to use in every of my UIViewControllers. The main UI is designed with Storyboard. The extra UIView has its own XIB.
So I don't want to put the UI of the extra UIView by hand into every UIViewController, and connect the outlets on every UIViewController. So I thought maybe it is possible to create the UI, and the connections in one XIB and then somehow reuse it. Is this possible? If yes how?
Just add this line to your ViewControllers to have a reference to your custom view:
YourView *yourView = (YourView *)[[NSBundle mainBundle] loadNibNamed:#"YourXIB"
owner:self
options:nil].firstObject;
But since you want this custom view in all of your ViewControllers, I recommend having one UIViewController subclass that contains the line above, then subclass that UIViewController for each additional one in your project. That way you'll have a reference to your custom view in each ViewController, but only have to write this line once.
I think it is possible by keeping the same name in the function initWithNibName:, so you can do this in one of your controller:
UIViewController *oneViewController = [[FirstViewControllerClass alloc] initWithNibName:#"MyXIBThatWillStayTheSame" bundle:nil];
[self presentModalViewController:oneViewController animated:YES];
and do this in another one:
UIViewController *anotherViewController = [[AnotherViewControllerClass alloc] initWithNibName:#"MyXIBThatWillStayTheSame" bundle:nil];
[self presentModalViewController:anotherViewController animated:YES];
I have a UIViewController that the root in a UINavigationController. What I'm doing there is I am instantiating another UIViewController of the same type, setting some properties and pushing it on top of the stack.
The problem here is that the parent view controller is also changing its property.
Here's how I'm doing it:
RootViewController *rootViewController = [[RootViewController alloc] initWithRequest:request];
[self.navigationController pushViewController:rootViewController animated:YES];
Why is this happening? Isn't this creating a new instance of the view controller and copying the same exact properties into a different object instance?
Both view controllers now have a pointer to the same request object. Any changes you make are reflected in both controllers. You probably need to copy the request object instead, if the controller is able to modify it.
I have a fairly simple iOS 5 app at this point.
A UINavigationController is set as the initial view controller in Interface Builder (do we still call it Interface Builder? anyways...). The UINavigationController has as its rootViewController a generic UITabBarController.
I want to use the main AppDelegate for both the UINavigationController and UITabBarController delegate's. I've made the AppDelegate conform to both the UINavigationControllerDelegate and UITabBarControllerDelegate. Everything works well. BUT!
In AppDelegate's application:didFinishLaunchingWithOptions:, I feel like I'm doing something hacky. I'm having to typecast self.window.rootViewController, and self.window.rootViewController.topViewController in order to set each controllers delegate.
UINavigationController *rootNavigationController = (UINavigationController *) self.window.rootViewController;
UITabBarController *rootTabBarController = (UITabBarController *) rootNavigationController.topViewController;
[rootNavigationController setDelegate:self];
[rootTabBarController setDelegate:self];
If I don't typecast self.window.rootViewController I can't set it's delegate. Same for the topViewController (UITabBarController).
If I've declared in Inferface Builder that the initial view is a UINavigationController, and not some generic UIViewController, why must I still typecast everything? Is this hacky?
Calling the property
window.rootViewController
returns an instance of UIViewController, and that class does not have a publicly visible property called delegate. UINavigationController, however, does.
When using property syntax (i.e., dot notation) the compiler needs to know which properties the receiver's class has declared.
If you instead do the standard message notation and don't cast, [rootViewController setDelegate:self], then it will probably work, but I believe you'll get a compiler warning still, but it will "work".
But it's generally good to be explicit. The compiler doesn't know how to properly/safely send the message -setDelegate: to UIViewController, that's why it complains. You need to be more explicit with it.
keep in mind that when you call self.window.rootViewController you are actually calling
[self.window rootViewController];
it's a method which returns a UIViewController object.
and the rootViewController property declared in UIWindow Class is belong to Class UIViewController.
The UIWindow object wouldn't know which class its rootViewController property is belong to, because setting the property is actually calling
[self.window setRootViewController:(UIViewController *) aViewController];
typecast has already happened here. The runtime would also use this method to implement outlet links you declared in xib.
So there's no way but to re-typecast it.
same case as rootNavigationController.topViewController
I might be confused here and asking the wrong question.
If I use a class like the UISplitViewController inside the appdelete.m, will the only message i will receive is the message the UISplitViewController calls and not any VIEW message? for example:
in my myappdelegate.m
....
UISplitViewController *mySplitViewController = [[UISplitViewController alloc] init];
mySplitViewController.viewControllers = [NSArray arrayWithObjects:leftside,rightside,nil];
...
mySplitViewController.delegate = self;
....
[windows addSubView:mySplitViewController.view];
....
-(void) viewWillAppear:(BOOL) animated {
}
in myappdelegate.h I included UISplitViewControllerDelegate
I expected viewWillAppear to fire but it is not. I assume if I had subclass UISplitViewControler it would have fire. right?
BTW: I am doing this without using IB. Do I need to set the target for the mySplitViewController?
What I want to do is setup the orientation of the splitviewcontroller when it rotates.
the viewWillAppear method and other view related methods will be called on the view or view controller themselves, not on the delegate.
That means that if you make a subclass of UISplitViewController called SplitViewControllerSubClass, the view... methods will be called on the instance of SplitViewControllerSubClass, not on the delegate object.
But considering you are creating the views and displaying them programmatically, you already know exactly when the view will appear (i.e., right before you add it to the window), so I believe you could do whatever setup you want at that point.