IPhone : View property on a Xib, is it special? - iphone

I can't believe I am stuck on this but here goes.
I have a viewController which I am trying to add to another viewController via the addsubview property (basic as) however I am not doing viewController.view but viewController.myView1.
I basically have 2 root views on the xib (both with outlets) however I don't want to wire up the view property of the xib because I want to choose which view to show.
I can't get it to appear! Is the view property some sort of special hook?
I can't see why addsubview:mysubview should not work?
Some examples seem to use 2 different xib's but that seems a overkill

Firstly, Apple say a viewcontroller should be used for a whole screen full of views - (but I guess iPad container views are different).
I guess you're wanting to only use one of the viewcontrollers at once. In which case you shouldn't be using subview - just create the viewcontroller programmatically, create the view, assign the view to the viewcontroller's view property and then add the viewcontroller to the window or navigation bar.
and, in your viewcontroller:
self = [super initWithNibName:nibOne bundle:nil];
might be what you want - it allows you to use multiple nibs with a single viewcontroller.

Can you NSLog your viewController.myView1 before add it as a subview? Is it nil or not?
If it's nil, try to add this line before your addSubview: method:
[viewController view];
Note: The viewController I am talking about is the same viewController which have two root views view and myView1.

Your code should be good as this is fairly simple and I do it all the time.
Just make sure your outlets are wired properly and that you are synthesizing them and that they are public in your header.

Related

titleView only works in one view controller (self.navigationController is nil)

I have a few navigation controllers that are set up in a NIB under a tab controller. I'm trying to set up the same logo in the top view controller of each navigationcontroller.
In the first view controller that appears, I have this code in viewDidLoad:
self.navigationItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"green-noback-logo-only.png"]] autorelease];
This works (well, almost, I'll have to resize the image) and replaces the text set up in the NIB with my logo image.
However, this exact same code doesn't work in either of the other two view controllers. Instead, any text I've set up for the title in the NIB shows. I've tried putting that code in initWithCoder, viewDidLoad, viewDidAppear and viewWillAppear and it does nothing. I'm explicitly setting leftBarButtonItem to nil, although I'm guessing it was nil to begin with. I have also already checked that self.navigationItem is not nil in any of the places where I'm trying to set the titleView.
Any idea what would be special about the other two controllers that would prevent them from having a titleView set? Otherwise, does someone have a more foolproof way to set titleView?
try setting the image view to self.navigationController.navigationItem instead of self.navigationItem.
tl;dr: I screwed up initWithCoder:.
A good wallbanger for a beginner. Following Paul N's answer, I discovered that self.navigationController == nil in the two broken view controllers. It took me another few hours of head-desking to figure out the rest.
All three top level view controllers were subclasses of UITableViewController. However, only two of them were using grouped style. I was overriding initWithCoder: to use initWithStyle: inside the two non-working table view controllers. This threw away the connection to the navigation controller stored in the NIB. I originally did this because I couldn't figure out how to set grouped style on those inside the NIB (suggested by another answer here).
Serves me right for subclassing in such a rotten fashion, I guess.
Anyway, the solution was to fix the initWithCoder: implementation to call [super initWithCoder:coder] as usual and set up the table view style in the NIB. I did this by dragging a table view under that view controller, setting the datasource, setting the delegate, and setting it to grouped style. (This is how table view controllers are set up in the NIB by default.)

iPhone Obj C - 2nd XIB How to configure a Nav Controller and View Controller

Still learning Obj-C slowly... forgive the dumb questions...
On my 1st XIB I have the App Delegate, Nav Controller and several view controllers. Along with that I have several buttons that calls a 2nd or 3rd or subsequent XIB.
The subsequent XIBS all have buttons which display views.
So on the 2nd+ XIB I have configured it in the .h as an UIViewController however I am guessing I need to make it something else like the primary .h is an AppDelgate.
So right now the XIB wants the view set, but I don't want it to go to a view, I want it to go to the view controller... I think??
Maybe I am still going about this all wrong. I need the primary menu to call the next menu (2nd XIB) which in turn calls various views. In my Java Android app I have about 70 classes, and guess and about 45 views so I am guessing again that I do in fact need the multiple XIBS.
So the question is how do I set up the additional XIBs? Are they AppDelegates or what?
Does that change the way I call the 2nd XIB?
The XIBs or the UIViews (or it's subclasses) are just the facial make up.
For the actually programming part, you deal directly among the "controllers" classes for these views.
View controllers that you make can have an XIB attached to them. But the behavior of how and when the view is shown or hidden, is all handled by the view controller itself.
So to come to the point, if you want to have a navigation bar on the top of you app (assuming that it's a simple app wanting to show many views with a navigation bar):
Create a UINavigationController instance in your applicationDidFinishLaunching: method in the app delegate:
// Assuming that mainViewController is the first controller + view for your app.
navigationController = [[UINavigationController alloc] initWithRootViewController:mainViewController];
[window addSubview:navigationController.view];
This will automatically add a navigation bar to your views. You don't need to add them manually in XIB or anywhere else. Now how you draw/implement mainViewController, is up to you.
When you want to show another view from within mainViewController, you should call:
AnotherViewController *anotherViewController = [[[AnotherViewController alloc] init] autorelease];
[self.navigationController pushViewController:anotherViewController animated:YES];
This will "push" your new view (from anotherViewController instance) into your navigation structure, which will automatically add a back button on the top.
Hope this helps clear the scene of how it works, a bit.
If you have doubts, comment about it. Have a great day!

How should I manage swapping a UINavigationController in and out of another UIViewController?

Here's what I have:
A MainWindow.xib file configured with one UIViewController (subclassed to RootViewController). This nib gets loaded at application launch.
RootViewController has two ivars, a custom subclass of UIViewController and a UINavigationController. Both of these are loaded from nibs.
When the application launches both ivars are initialized from their respective nibs, and then the UIViewController.view is added as a subview of RootViewController.view.
Inside UIViewController's view I have a control that triggers an animated swap of UIViewController and UINavigationController. This is where the problem comes in. The swap animates, but the UINavigationController's views are not properly displayed. I get a Navigation Bar with no title, and nothing else.
The UINavigationController nib and underlying functionality have been tested in a stand alone project, but there was no RootViewController.
So, my question is, can I even do this? I've successfully swapped other view controllers like this, but never a UINavigationController. I've seen some documentation that leads me to believe this might be a fools errand, but I haven't convinced myself of that yet.
Solution (Kinda):
I found a solution (workaround? hack?), but it leads to some more questions. I nixed using a Nib for the UINavigationController. Instead, I loaded my UINavigationController's rootViewController from a Nib and then created the UINavigationController programmatically with initWithRootViewController:.
NavRootViewController *navRoot = [[NavRootViewController alloc] initWithNibName:#"NavRootViewController" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:navRoot];
[navRoot release];
This works as I expect. Which leads me to the conclusion that the rootViewController property of the UINavigationController wasn't being set properly when I loaded navigationController from a Nib. And the question is, why? Should it?
Also, when you see something like this happening in one case, but not another, it can be beneficial to either create a subclass and make your nib point at that subclass, or if you already have a subclass use that.
In the subclass, override all the various init:, initWithNibName:bundle:, viewDidLoad:, viewWillAppear:, viewDidAppear: and any other appropriate methods, and in those override, just NSLog("") something about which method it is (with param values perhaps) and call the super implementation.
This will give you an observable "track" of which methods are called in which order, and you can set a breakpoint to see where that call comes from.
This will give you enough information to find missing method calls, and then you can pursue the correct problem either here, or through filing a radar or ...
In some cases, viewDidLoad and viewDidAppear or awakeFromNib may need to be called each time you add the UINavigationController back into the stack of UIViewControllers. It seems that when the typical code executes out of your AppDelegate, that the Window, or something behind the scenes is doing something special for UINavigationController that presentModalViewController doesn't do.
I think you may have missed a conceptual point.
A UINavigationController controls view controllers instead of views. It controls when and where view controllers themselves are loaded. The views themselves are loaded only as a side effect of the pushing and popping of their respective controllers.
Therefore, putting a navigation controller inside of a view controller seldom makes much sense.
If I understand what you are trying to do correctly, you should have the RootController actually set as the rootController property of the UINavigationController (yes the nomenclature is extremely confusing.) Then when your swap event occurs, you should have the navigation controller push the next view. The RootController view will disappear to replaced by the other. then you can repeat the process for an arbitrary number of view controllers.
Only in the case of a tabbar would you want a navigation controller to be a property of a view controller. Even then it should be at the top the tab's hierarchy.

superview and parentviewcontroller nil after adding a subview

I think I'm missing something fundamental and so I want to ask the community for some help. I'm building an app based around a basic iPhone Utility Application. My MainView and FlipsideView share some elements so I have created separate ViewControllers and nib files for those pieces. In order to do this I have done the following:
1. Created a viewcontroller called searchDateViewController which is the file's owner of searchDateView.xib
2. searchDateView.xib is basically a UIView with a UILabel inside, the view is wired up correctly
3. Inside both MainViewController.m and FlipsideViewController.m I add a subview as folllows:
- (void)loadView{
[super loadView];
searchDateViewController = [[SearchDateViewController alloc] initWithNibName:#"SearchDateView" bundle:nil];
[[searchDateViewController view] setFrame:[searchDateView frame]];
[[self view] addSubview:[searchDateViewController view]];
...
}
Everything displays and works just fine. Basically depending on actions that happen in each of the main and flipside views the UILabel of the nib is changed. However, I wanted to do something slightly different if the searchDateViewController is loaded from the MainView or the FlipsideView. However, I can't seem to figure out which ViewController is adding the searchDateViewController subview.
In searchDateViewController I tried:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"superview %#", self.view.superview);
NSLog(#"parentviewcontroller %#", self.parentViewController);
}
In both cases I get nil.
So my question is - can I find out which ViewController is adding searchDateViewController a a subview? If so how? Or if my logic here is completely messed up, how should I be doing this?
Thanks!
viewDidLoad is invoked when the view controller has loaded its view. In your case, that happends in this line:
[[searchDateViewController view] setFrame:[searchDateView frame]];
At that moment, you haven't yet called addSubview: so it is no wonder the view's superview is nil.
To solve your problem, you should define a property inside SearchDateViewController to distinguish between the different cases. This property would then be set accordingly by the parent controller that creates the SearchDateViewController instance.
Generally, I do not think it is a good idea to use a UIViewController subclass as a controller for a view that is used as a subview of one or several fullscreen views rather than be used as a fullscreen view itself. Much of UIViewController's logic works on the assumption that it is used to manage a fullscreen view. For instance, with your design, I think it's possible that SearchDateViewController will modify the view's frame when the device orientation changes etc. Since you don't need all this functionality for a non-fullscreen subview, I suggest you subclass your SearchDateViewController directly from NSObject.
ViewController and views are completely separate.
In most cases, when you add a subview to a parent view you don't add its controller to the parent's viewController. The exception to this rule is the navigation controller which adds the controller instead of the view to maintain a hierarchy of view controllers.
Your SearchDate viewController can't find a parent controller because you never assigned one and the system does not do it automatically. You can just assign a parent controller when you evoke the view from another controller.
searchDateViewController.parentController=self;

iPhone SDK: How to display a view controller within another?

Fundamentally, what I want to do is within, for example, ViewControllerA display ViewControllerB and ViewControllerC. How would I do that?
Thanks in advance.
You don't display view controllers, you display views. Having said that, you can do something like this:
UIViewController *a = ...;
UIViewController *b = ...;
[a.view addSubview:b.view];
Now, having said that, you shouldn't do it. Tons of stuff does not behave properly, because there are tons of undocumented interactions between UIView, UIWindow, and UIViewController. There is nothing in the documentation that says it won't work, but random things stop behaving properly (viewWillAppear: on the interior view's VC doesn't get called, etc).
If you need this functionality, you should file a bug with Apple.
The default template for a navigation view controller should do what you want assuming you want two different screens (not two different sections on the same screen). Whenever you want to change the view from the current one to another, just tell the navigation controller to push it on the stack:
[self.navigationController pushViewController:viewBoards animated:YES];
The default navigation view controller gives you a root view controller with a navigation view controller in it. It also gives you one view controller called MainWindow. Just add as many copies of MainWindow as you need to get your functionality.