7 Replies Latest reply: May 15, 2010 5:56 AM by zoodany
zoodany Level 1 Level 1 (0 points)
Hi.
I've created a TabBar application with two tabs.
The second tab is a NavigationController that display an UITableView correctly.
When I select a cell of this TableView I would display another UITableView.

I wrote this:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

TipoPartitaController *menuImp;
if (indexPath.row == 0){
//l'utente ha cliccato sull'elemento iPhone, quindi carichiamo la vista relativa
menuImp = [[TipoPartitaController alloc] initWithNibName:@"TipoPartita" bundle:[NSBundle mainBundle]];
} else {
//menuImp = [[OtherDetailController alloc] initWithNibName:@"OtherDetail" bundle:[NSBundle mainBundle]];
}

//Facciamo visualizzare la vista con i dettagli
[self.navigationController pushViewController:menuImp animated:YES];
//rilasciamo il controller
[menuImp release];

menuImp = nil;
}

where TipoPartitaController is the UITableViewController that I want to display.

When I select the first cell the method above is called (i can debug it) but then the app crash and in the console there's no error reported.

What's wrong?

Thank you very much.
Daniele.

Message was edited by: zoodany

Message was edited by: zoodany

MacBook, Mac OS X (10.6.3)
  • sptrakesh Level 4 Level 4 (1,785 points)
    You should be able to see where the app crashed in the debugger. If not, set a break point at the entry of the method and step through to see where the crash occurs.
  • zoodany Level 1 Level 1 (0 points)
    Actually the execution reaches the end of the method without crashing, AFTER the end of the method it crashes..

    Any idea?!
    Thank you
    Daniele.
  • sptrakesh Level 4 Level 4 (1,785 points)
    It may be the nib you are trying to load. Can you try loading the VC directly from your app delegate for instance to see if that is the problem.
  • RayNewbie Level 5 Level 5 (6,810 points)
    Hi Daniele -

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UIViewController *menuImp = nil; // <-- 1) more general class and init to nil
    if (indexPath.row == 0){
    //l'utente ha cliccato sull'elemento iPhone, quindi carichiamo la vista relativa
    menuImp = [[TipoPartitaController alloc]
    initWithNibName:@"TipoPartitaController" // <-- 2) verify name of the xib
    bundle:[NSBundle mainBundle]];
    } else {
    //menuImp = [[OtherDetailController alloc]
    // initWithNibName:@"OtherDetail"
    // bundle:[NSBundle mainBundle]];
    }
    NSLog(@"menuImp=%@", menuImp);
    //Facciamo visualizzare la vista con i dettagli
    [self.navigationController pushViewController:menuImp animated:YES];
    //rilasciamo il controller
    [menuImp release];

    menuImp = nil;
    NSLog(@"End tableView:didSelectRowAtIndexPath:");
    }

    Your code is correct, and I'm guessing the only problem is with the spelling of the xib file name. Check that and see if it isn't something like "TipoPartitaController" as shown in commented line 2.

    An error in the first arg of initWithNibName:: is quite difficult to isolate without manually comparing the arg string to the actual file name. This is because (for some reason!) the method returns a non-nil pointer regardless of whether the named xib file is found. Thus neither the debugger nor NSLog() will detect the problem. Your code then crashes at some point during the task of pushing the uninitialized controller object onto the nav controller's stack and attempting to display that controller's view. I've never seen that particular crash produce any diagnostic message in the Console.

    If the return from a failed initWithNibName:: were nil (as it should be), you'd simply get a runtime warning without a crash on the attempt to push the nil pointer onto the stack. If this is never going to be fixed in UIViewController, I think we should at least get a warning in the doc.

    The change in commented line 1 is optional, but I think it will help you when testing with additional view controller classes. By typing menuImp as UIViewController*, it might be less easy to make a mistake when that var points to an object which isn't an instance of TipoPartitaController. It might also be helpful to init that var to nil. For example when running the above code, if you select row 2 or 3, you'll get a runtime warning like "Application tried to push a nil view controller ..." instead of a crash.

    - Ray
  • zoodany Level 1 Level 1 (0 points)
    Hi Ray,
    thanks for your time..
    The name of the xib is correct, if I change it i get this error:
    '-[UIViewController _loadViewFromNibNamed:bundle:] was unable to load a nib named "WrongXibName"

    The instruction NSLog(@"End tableView:didSelectRowAtIndexPath:"); is normally executed.

    A thing that I haven't specified is that the xib doesn't contain an UIView but an UIViewTableViewController and an UIViewTableView, it can be a problem? Also I'm not sure if what tyou can see in the image at this link ( http://www.zoodany.it/Schermata.png ) is correct....

    Thank you again.
    Bye.
    Daniele.
  • RayNewbie Level 5 Level 5 (6,810 points)
    zoodany wrote:
    The name of the xib is correct, if I change it i get this error: ...

    Maybe initWithNibName:: finally got fixed! I'm still using SDK 3.1.2
    ... the xib doesn't contain an UIView but an UIViewTableViewController and an UIViewTableView, it can be a problem?

    No, that's not a problem.
    !http://www.zoodany.it/Schermata.png!
    The xib includes a second object of TitoPartitaController type. If the Table View object is connected to that second object instead of File's Owner, that's the problem.

    To understand this, note that \[\[TipoPartitaController alloc\] initWithNibName:...:...\] has already created the controller object you want, and that controller will be connected to whatever the File's Owner "proxy object" is connected to in the xib.

    The controller object in the xib causes a second controller to be created. But the second controller isn't connected to the code. In other words, the address of the second controller isn't saved in any variable. Because of this, the second controller can't be retained, so since top level xib objects are autoreleased, the second controller will be deallocated at the end of the event cycle in which the xib was loaded.

    Deallocing the second controller wouldn't be a problem if the table view object were connected to File's Owner. But otherwise, we would expect a crash--as explained above--at the end of the event cycle. I.e. after tableView:didSelectRowAtIndexPath: runs.

    Anyway, if my explanation didn't make sense or was too tedious to finish, the good news is this problem should be easy to fix:

    1) Open the TipoPartita.xib window and select the Tipo Partita Controller object in the third row;
    2) Select Edit->Delete from the top menu bar;
    3) The Tipo Partita Controller object as well as the Table View belonging to it should now be gone;
    4) Drag a new Table View object from the Library into the xib file;
    5) Connect the 'view' outlet of File's Owner to the Table View;
    6) Connect the 'dataSource' outlet of the TableView to File's Owner;
    7) Connect the 'delegate' outlet of the TableView to File's Owner;
    8) Save the xib.

    Your project should now run without any further changes to the code.
    \- Ray
  • zoodany Level 1 Level 1 (0 points)
    Great!
    Thank you very much Ray! Really..

    Bye.
    Daniele..