1

I'm going mad using navigation controllers on the iPhone. I have an app, with a main xib (the one with the window) inside wich I have put a NavigationController, inside wich I have a viewController. Everything is connected and the ViewController is defined with the correct inherited class name.

In the didFinishLaunchingWithOptions, i have :

[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];

In the .h I have :

@interface MainAppDelegate : NSObject <UIApplicationDelegate> {
    IBOutlet UIWindow *window;
    IBOutlet UINavigationController* navigationController;
}

@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) UINavigationController* navigationController;

@end

Then in the First ViewController I have a button connected to this method :

- (IBAction) definePreferences:(id)sender {
    PreferencesController *nextWindow = [[[PreferencesController alloc] initWithNibName:@"Preferences" bundle:nil] autorelease];        
    UINavigationController* navController = [[[UINavigationController alloc] initWithRootViewController:nextWindow] autorelease];
    [self.navigationController presentModalViewController:navController animated:YES];
}

all items in the main xib seems to be connected... and retained by the properties. The AppDelegate with its window and navigationController... the Window rootviewcontroller with the same navigationController... and the file owner with the app delegate...

Everything runs fine, but the preferences window never appears...

Can you see why ?

If needed, I must say that this first view controller makes the camera interface appear and put an overlay over it. The button is onto this overlay. The imagePicker is show like this in viewDidAppear :

UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[self presentModalViewController:picker animated:YES];
    [picker release];

EDIT : In viewDidAppear, self.navigationController is ok at the start and end of method. In definePreferences, self.navigationController is nil. Nothing is called beetween those two calls. Nothing

EDIT : The problem may come from the way I init the viewController on which the button is. Here is the method called from the firstView called by the Navigation Controller.

- (void) viewDidAppear:(BOOL)animated {

    UIImagePickerController* picker = [[UIImagePickerController alloc] init];

    // Set the image picker source:
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;

    picker.showsCameraControls = NO;
    picker.navigationBarHidden = YES;
    picker.wantsFullScreenLayout = YES;

    // Insert the overlay
    OverlayViewController* overlayController = [[OverlayViewController alloc] initWithNibName:@"Overlay" bundle:nil];
    picker.cameraOverlayView = overlayController.view;

    // Show the picker:
    [self presentModalViewController:picker animated:NO];
    [picker release];

    [super viewDidAppear:YES];
}

But... how should I do ?

Oliver
  • 21,876
  • 32
  • 134
  • 229
  • Have you checked that your `setPreferences:` method is actually being called when you touch the button, e.g. with a logging statement or a debugger breakpoint? – Anomie Mar 15 '11 at 01:31
  • 1
    Note that neither your window nor navigationController are going to be retained, because you have IBOutlet set on the ivars rather than the properties. So the ivar ends up being set directly without going through the setter methods that would `retain` them. – Anomie Mar 15 '11 at 02:22
  • @Anomie is correct, and the IBOutlet should be on the properties, but I doubt this is the problem, or you'd crash rather than get nil. – Rob Napier Mar 15 '11 at 03:57
  • @Rob Napier : Uhhhhh, are you sure ? I don't want to talk about something I'm not sure, but I've made a BIG project built this way, with the IBOutlet set on the ivars, and everything works fine, retained, copyed, assigned, ... – Oliver Mar 15 '11 at 11:02
  • @Oliver While it is possible to get things to work correctly with IBOutlet on the ivar, it is fragile. If your ivar and property have different names (which they should), it will under-retain on memory warning, and you will have dangling ivar pointers, which is very dangerous (though again, you might get away with it). A good discussion of this is in this question: http://stackoverflow.com/questions/1250518/what-happens-if-i-dont-retain-iboutlet See particularly the link to the Memory Management page from Apple. Putting IBOutlet on the @property is best practice for safety. – Rob Napier Mar 15 '11 at 13:41

2 Answers2

1

First, never call an IBAction setPreferences:. That violates KVC, and can eventually cause all kinds of bizarre behaviors. setX: is a reserved name for the setter of the property named x.

You should not be creating a nav controller in this method (i.e. navController). You should be using the one you created in the NIB (self.navigationController). Check if that is nil. If it is, then you either didn't set up a navigation controller in the NIB, or you didn't wire it to this view controller.

You should also verify that nextWindow is non-nil.

Rob Napier
  • 250,948
  • 34
  • 393
  • 528
  • @Rob Napier : Ok, I renamed the method. I only call [self.navigationController presentModalViewController:nextWindow animated:YES]; after the nextWindow allocation. nextWindow is not nil. Still nothing... self.navigationController is nil, but I can check everything in the xib, all items seems to be connected... and retained by the properties. The AppDelegate with its window and navcontroller... the Window rootviewcontroller with the same navigationController... and the file owner with the app delegate... Any idea of what is going wrong ? – Oliver Mar 15 '11 at 01:15
  • "self.navigationController is nil" ← That's your problem. Calling `presentModalViewController:animated:` on a nil object won't do anything. – Anomie Mar 15 '11 at 01:42
  • @Anomie : yes, I know, but what is wrong ? Things seems well connected. Calls seems to be the good ones. So what... ? – Oliver Mar 15 '11 at 01:57
  • @Oliver Could you clean your project for all target and build it again.Also delete your application from simulator ... – Jhaliya - Praveen Sharma Mar 15 '11 at 02:55
  • 1
    Your comment about viewDidAppear makes me wonder if you might have multiple copies of the view controller. NSLog(@"%@", self) and make sure you're always looking at the same object. You can also override `setNavigationController:` and see who's calling it. – Rob Napier Mar 15 '11 at 03:59
  • @Jhaliya : I'll try when back home and I'll tell what happened. Just to know, isn't it possible to raise a view from scratch without having defined a UINavigationController in the main window ? – Oliver Mar 15 '11 at 16:57
  • @Rob Napier : you where right, I had 2 instances. I rewrote the code to get only 1 instance, but still the same problem. See my EDIT. I suppose the navigation controller is not transmitted to the overlay. But how can I transmit it ? – Oliver Mar 15 '11 at 19:32
0

I've finaly solved the problem. See https://stackoverflow.com/questions/5317968/iphone-camera-overlay-going-down-after-a-modal-view-transition

I have some hair less... :-)

Community
  • 1
  • 1
Oliver
  • 21,876
  • 32
  • 134
  • 229