Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Tab Bar Controller - Navigation Controller - TableView

BostonMerlinBostonMerlin Posts: 399Registered Users
edited December 2011 in iOS SDK Development
I am having a bear of a time getting this to work. I've looked at it so many ways and followed tutorials on how to set each of the controllers separately but none show how to combine them all.

super simple bare bones sample

- create new Tab Bar Application
- create a new FirstScreenViewController .h and .m class
- add the appropriate TableView methods (as explained in other articles)
- Create a new FirstScreen.xib with a UIView
- Drop a TableView onto the View
- set the files owner to point to FirstScreenViewController
- Save to project
- load up MainWindow.xib
- set the first tab to be a Navigation Controller
- set the first tabs xib to point to the FirstScreen.xib file

Save and run. I see a TabBar window with two buttons. the first button has a navigation controller toolbar up top and i can see the outlines of an empty Table View. Looks great so far.

Load up my FirstScreenViewController.xib file. Connect the view, tableview datasource and tableview delegate to point over to the Files Owner. Save

Run the project, hangs for a second then dumps me back to xcdoe with an unhandled error. Take out the datasource and delegate connections and i'm back to see a blank tableview.

Any Ideas? I know this is a long winded desription.. sorry. I'm able to create a single page application with a tableview with no problem but when i dump this into a tabbar controller it craps out.

if you have any ideas please show me the light!

Thanks
John
Post edited by BostonMerlin on

<br />
<b>I love being a dad, flying airplanes and writing code.</b><br />
<br />
Follow me on Twitter: <a href=
«13456714

Replies

  • cmezakcmezak Posts: 207Registered Users
    edited August 2008
    Have you pushed the tableview onto the navigation controller's stack?

    you might try setting the tableViewControllers' delegates and datasources programatically just in case you're unintetionally doing something weird in interface builder.

    I've done all of my development programatically so far, because I like to see things explicitly spelled out, not hidden behind a gui the way they are in IB.

    Good luck!

    Charlie
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    I will contact you in private with a template and some help. I found the same issue and a complete and easy way around it.
  • BostonMerlinBostonMerlin Posts: 399Registered Users
    edited August 2008
    I will contact you in private with a template and some help. I found the same issue and a complete and easy way around it.

    Thanks DevTeam. I received your PM. If you have an outline of what i should do to simplify this even more please post in the thread so others who might be having the same problem can learn from your suggestions as well!

    Thanks a million!
    John

    <br />
    <b>I love being a dad, flying airplanes and writing code.</b><br />
    <br />
    Follow me on Twitter: <a href=
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    The issue is actually fixed by forgetting about a TabBarController application. Do everytihng on a basic application basis.

    Create your tab bar controller programatically, and your navigationcontroller programmatically too.

    then create a UITableViewController and add that to the NavController created in the App Delegate. Add that NavController to the Tab Bar Controller. Add the Tab Bar Controller's view to the window.

    Do everything in the App Delegate to do with TabBarControllers and Navigation Controllers. They are simple and easy to make programatically, so why on earth muddle it up with Interface Builder. The fact is, that the templates provided in Xcode have never been the simplest. They have actually been pathetically convoluted. Just create a navigation controller and tab bar controller, add the view Controller to the nav controller, and add the nav controller to the tab bar controller.

    I use Interface builder sparingly. It often makes things far more complicated. This is one example of it. NavControllers and TabBarControllers should NEVER be made via interface builder, but by code. Apple never uses interface builder for this, as its way too stupidly set up. The programing way to do it is simpler, and far more understandable when you understand a bit of Objective-C.
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    Does you require a bit of code to show you how to set these up programatically?
  • BostonMerlinBostonMerlin Posts: 399Registered Users
    edited August 2008
    that would be great.. thanks! I appreciate you taking the time
    - John

    <br />
    <b>I love being a dad, flying airplanes and writing code.</b><br />
    <br />
    Follow me on Twitter: <a href=
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    @interface AppDelegate : NSObject <UIApplicationDelegate> {
        UIWindow *window;
        UITabBarController *tabBarController;
        MyTableViewController *myTableViewController;
        MySecondTableViewController *mySecondTableViewController;
    }
    
    @property (nonatomic, retain) IBOutlet UIWindow *window;
    @property (nonatomic, retain) UITabBarController *tabBarController;
    @property (nonatomic, retain) MyTableViewController *myTableViewController;
    @property (nonatomic, retain) MySecondTableViewController *mySecondTableViewController;
    
    @end
    
    
    
    
    @implementation AppDelegate
    
    @synthesize window, myTableViewController, mySecondTableViewController, tabBarController;
    
    - (void)applicationDidFinishLaunching:(UIApplication *)application {
    
           tabBarController = [[UITabBarController alloc] init];          // creates your tab bar so you can add everything else to it
    
           myTableViewController = [[MyTableViewController alloc] init];               // creates your table view - this should be a UIViewController with a table view in it, or UITableViewController
           UINavigationController *tableNavController = [[[UINavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
           [myTableViewController release];                                                              // creates your table view's navigation controller, then adds the view controller you made. Note I then let go of the view controller as the navigation controller now holds onto it for me. This saves memory.
    
           mySecondTableViewController = [[MySecondTableViewController alloc] init];   
           UINavigationController *table2NavController = [[[UINavigationController alloc] initWithRootViewController:mySecondTableViewController] autorelease];
           [mySecondTableViewController release];                                                    // does exactly the same as the first round, but for your second tab at the bottom of the bar.
    
           tabBarController.viewControllers = [NSArray arrayWithObjects:tableNavController, table2NavController, nil]; add both of your navigation controllers to the tab bar. You can put as many controllers on as you like, but they will turn into the more button like in the iPod program.
    
           [window addSubview:tabBarController.view];                                              // adds the tab bar's view property to the window
           [window makeKeyAndVisible];                                                                  // makes the window visible
    }
    
    - (void)dealloc {
           [tabBarController release];
           [window release];
           [super dealloc];
    }                                           // lets go of everything else, thats so your program doesn't create any leaks of memory.
    
    @end
    


    I just typed up this quick App Delegate to show you how to do it. Yes, you do have rights to use whatever part of it you wish, and yes, you can ask any questions you like.

    Please do note:
    a ) I release the table views because they have been retained by the Navigation Controllers. Thus, I have doubled up and am taking double the memory. Once you have a nav controller holding your view, drop it. This saves memory. These nav controllers are set to drop automattically with their autorelease so there is no leak issue.

    b ) if you need to add only one item to your tabBar for some strange reason, or just to test, change "arrayWithObjects: blah, blah2, nil" to "arrayWithObject: blah" and drop the nil. :)

    Does this help you???
  • BostonMerlinBostonMerlin Posts: 399Registered Users
    edited August 2008
    Thanks Dev. I was able to get that code running with one tab showing a UINavigationController and a table full of data and the other tab showing a UIViewController with a page of labels and buttons. Very nice.. thank you!

    I am hitting a wall though. Using your code i've tried any number of ways to add content below the nav bar but above the tableview. I'm trying to get the following look for this app....


    Pseudo Description:
    - App should have a tabbar at the bottom with two tabs
    - the first tab shows a navigationcontroller up top, label and image below it followed by a tableview.
    - the second tab shows labels and images.

    For whatever reason the tabbar is the big pain! I know this isnt rocket science.. it's just not clicking. I can perform these tasks w/out the tab bar but throw that into the mix and i'm getting nothing but a white page on that first tab.


    Thanks Again
    JB








    Any thoughts? Thanks again for your help.
    John

    <br />
    <b>I love being a dad, flying airplanes and writing code.</b><br />
    <br />
    Follow me on Twitter: <a href=
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    OK.

    A UINavigationController can hold any type of UIViewController. If its subclassed under the UIViewController type, a NavigationController can hold it. Just remember though, that without scrolling capabilities, and with your tab bar, you need to accomodate that in your viewcontroller, and not put anything more than a nagivationbar AND a tab bar's away from the bottom. Just be careful there :)

    There are several options I can think of with your little issue there.

    One is to add what you are trying to do as a header to the TableView. Check out the TableViewProgramming guide and you will learn you can put a header over the top, and a footer underneath, the table view you are working on. You can also do section headers too.

    The other option, and one I have never tried, (and don't really want too as I feel it has a 50/50 chance of not working ) is to try adding a UITableView to a viewController, and fixing that viewController up correctly. I don't know if this will work, but you would then need to add that UIViewController (an instance of it anyway) to your tab bar.



    Something I forgot to mention before. Remember that the name on your tab bar and in the navigation controller is set by this code in the first viewController or TableViewController you add to the navigation bar:
    self.title = @"name";
    

    And your tab bar image is set by:
    self.tabBarItem.image = [UIImage imageNamed:@"tabbarimage.png"];
    

    BTW, do you see how easy it is to do it without IB? IB drives me nutty like this... and still people use it :s
  • BostonMerlinBostonMerlin Posts: 399Registered Users
    edited August 2008
    good idea regarding the tableview header. i'll have to check it out but my initial thought is it might not work for me as i dont want that header (with the image and labels) scrolling up and off the screen when the user scrolls the table down. I want the label and picture to be fixed at a position above the table. That might be the gotcha.

    I'll play around with the header though.. maybe there's a fixed-to-view property or something like that..

    Thanks again
    John

    <br />
    <b>I love being a dad, flying airplanes and writing code.</b><br />
    <br />
    Follow me on Twitter: <a href=
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    UINavigationController is a very strict class, btw. You seem to be playing around with it from what you were saying, though you were a bit difficult to follow at the end.

    Simply add whatever view you want into the NavigationController via the initWithRootViewController method.

    Also make sure that you always create the navigationController IN THE APP DELEGATE!!!!! That Is SOOO important. I have seen a few apps on App Store with the stupid error of subclassing UINavigationController in another place other than the app delegate.

    Never play around with NavigationController by subclassing it. There is NO reason to, and it creates an error as the navigationController compensates for the status bar at the top of the view. This leaves a big black hole wherever it was subclassed.

    Points to take away:

    NEVER subclass UINavigationControllers. (same also applies with UITabBarControllers]
    Just add whatever ViewController you want via the initWithRootViewController: method

    Check out the View Controller Programming Guide for more ideas of what to do with navigationControllers.
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    good idea regarding the tableview header. i'll have to check it out but my initial thought is it might not work for me as i dont want that header (with the image and labels) scrolling up and off the screen when the user scrolls the table down. I want the label and picture to be fixed at a position above the table. That might be the gotcha.

    I'll play around with the header though.. maybe there's a fixed-to-view property or something like that..

    Thanks again
    John

    I don't believe there is one of those.

    Perhaps add a tableView as i said...


    Still have a play. :) also, don't overstep your bounds. Theres some things which simply aren't possible. Know when to quit, and alter your ideas according to the restrictions.

    oh, well, enough commands from me :)
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    Oooh... just had an idea... you can create tableViews without TableViewControllers. Just set your viewController as the delegate and datasource and it shouldn't be an issue.

    Then you could add the tableView as a subview (as you can change it in interface builder if you want to...) and then add the section as a fixed section also by the same UIViewController
  • BostonMerlinBostonMerlin Posts: 399Registered Users
    edited August 2008
    Oooh... just had an idea... you can create tableViews without TableViewControllers. Just set your viewController as the delegate and datasource and it shouldn't be an issue.

    Then you could add the tableView as a subview (as you can change it in interface builder if you want to...) and then add the section as a fixed section also by the same UIViewController

    Not sure i completely follow you on this one. I'll have to sit on the idea for a while so that i can focus on the rest of the app.. maybe it'll make sense to me later on. I know it's something simple.

    This can't be as difficult as i'm making it...
    - App should have a tabbar at the bottom with two tabs
    - the first tab shows a navigationcontroller up top, label and image below it followed by a tableview.
    - the second tab shows labels and images.


    Thanks for all your help.. i picked up a few things going down this rabbit hole.
    John

    <br />
    <b>I love being a dad, flying airplanes and writing code.</b><br />
    <br />
    Follow me on Twitter: <a href=
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    It was quite simple. In your first tab, create a UIViewController that is controlled by the UINavigationController. In that view Controller, place the label and the image at the top, then put in your tableview below it.
    You don't need a tableViewController to create a table view. your UIViewController can act as your controller for the table view.
  • RockStrongoRockStrongo Posts: 176Registered Users
    edited August 2008
    I was having a similar issue with IB, so I decided to try your code Dev.....We get this error though...

    2008-08-16 16:39:45.134 AppTab[16817:20b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFArray insertObject:atIndex:]: attempt to insert nil'
    2008-08-16 16:39:45.136 AppTab[16817:20b] Stack: (
    2454909259,
    2496749819,
    2454908715,
    2454908778,
    2465199056,
    2464274948,
    2464274708,
    816674028,
    816673653,
    816663945,
    10054,
    816174362,
    816210018,
    2464512350,
    2454412101,
    2454412536,
    829005112,
    829005309,
    816175835,
    816221412,
    9888,
    9742
    )

    It seems to be failing on this line...

    UINavigationController *tableNavController = [[[UINavigationController alloc] initWithRootViewController:listTableViewController] autorelease];
    [listTableViewController release];

    Ideas?
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    You don't technically need to release listTableView until dealloc. Move your release of listTableView to there and try. I had this error a few times. It's just released there for memory management.

    Try it there and let us know how u go.
  • RockStrongoRockStrongo Posts: 176Registered Users
    edited August 2008
    You don't technically need to release listTableView until dealloc. Move your release of listTableView to there and try. I had this error a few times. It's just released there for memory management.

    Try it there and let us know how u go.

    Yeah I tried that and it didnt work. Here is my h file....am I missing something?

    @class AppTabViewController;

    @interface AppTabAppDelegate : NSObject <UIApplicationDelegate, UITabBarDelegate> {
    UIWindow *window;
    UIViewController *listTableViewController;
    UIViewController *myInfoTableViewController;
    }

    @property (nonatomic, retain) UIWindow *window;
    @property (nonatomic, retain) UIViewController *listTableViewController;
    @property (nonatomic, retain) UIViewController *myInfoTableViewController;

    @end
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    that's your interface file, could you post ur implementation file ( I think I know the issue, just need to make sure)
  • RockStrongoRockStrongo Posts: 176Registered Users
    edited August 2008
    #import "AppTabAppDelegate.h"

    @implementation AppTabAppDelegate


    @synthesize window, listTableViewController, myInfoTableViewController;

    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    UITabBarController *tabBarController = [[UITabBarController alloc] init];

    UINavigationController *tableNavController = [[[UINavigationController alloc] initWithRootViewController:listTableViewController] autorelease];

    UINavigationController *table2NavController = [[[UINavigationController alloc] initWithRootViewController:myInfoTableViewController] autorelease];

    tabBarController.viewControllers = [NSArray arrayWithObjects:tableNavController, table2NavController, nil];

    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];
    }

    - (void)dealloc {
    [window release];
    [listTableViewController release];
    [myInfoTableViewController release];
    [super release];
    }

    @end
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    The issue you are having is quite simple.

    The template I created was based upon those viewControllers being synthesized from an IBOutlet. Yours, however, are not.
  • DevTeamOfOneDevTeamOfOne Posts: 361Registered Users
    edited August 2008
    To mitigate this, add the following two lines:
    listTableViewController = [[ListTableViewController alloc] init];
    myInfoTableViewController = [[MyInfoTableViewController alloc] init];

    also move your releases back to the positions you had them, straight after you added each of the viewcontrollers to their respective navigation controllers.

    add the lines i mentioned before you create each of those navigation controllers. Add the myInfo one after the release of listTableViewController, to save on memory. Loading lazily and releasing early is good practice for apps that may become very high in memory usage.
  • RockStrongoRockStrongo Posts: 176Registered Users
    edited August 2008
    Awesome.....looks like that did the trick! Thanks!
  • svguerin3svguerin3 Posts: 147Registered Users
    edited August 2008
    This is a great thread for getting started with tab-bar setup. Quick dumb question, though. In my sample app, I have 2 tabs, the first one is pointing to a UINavigationViewController class, and the other is pointing to a regular ViewController class. It's working great, and it's allowing me to add navigation buttons, etc, to the first tab using the above-mentioned example code, but what I want is to have a TableViewController in the Navigation window (tab #1), in order to contain a list for selection within the Navigation. Or if there is a better way to do this, please let me know (I'm quite new to this).

    How can this be easily accomplished via the code? I really want to avoid using IB in any of this part of my test app, and I can't find many examples of creating this without IB out there..

    Thanks in advance!
  • svguerin3svguerin3 Posts: 147Registered Users
    edited August 2008
    Disregard my last post. My issue was just that I was not including the CoreGraphics framework. It's working great now. Thanks!
«13456714
Sign In or Register to comment.