This is part of an ELC Tech Network

iPhone Programming Tutorial – Using A TabBarView To Switch Between Views

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

In this tutorial I will show you how to develop a UITabBarController which contains a custom UIView from one of the tabs and a UINavigationController with a UITableView dictated byUISegmentControl in the second tab.

This tutorial was contributed by the user cruffenach.  You can check out his website at http://losectrl-gaincommand.com.

If you would like to contribute a tutorial to iCodeBlog.com, contact me brandon@icodeblog.com

[ Javascript required to view QuickTime movie, please turn it on and refresh this page ]

The final product of this tutorial should look something like this:

Setting up the User Interface

The first thing we need to do is open up MainWindow.xib. This will launch interface builder and show what our UITabBarController looks like. In the first tab we see a custom UIView that can be changed however we like, but we are more concerned about the second tab.

Clicking on the TabBarController within the instance window of interface builder and then looking to the Inspector will let us set the type of view controller which each tab will be displaying. The first tab uses a ViewController, and for the second tab we want to use a Navigation Controller type because we will be utilizing the navigation bar to hold our segmented control.

Once in the second tab, we will drag a UISegmentedControl out of our library and onto the navigation bar. The UISegmentedControl will change its look depending on the context you place it in. Here we will essentially be making the TitleView of the NavigationItem a UISegmentedView. This will be important when we get into our code.

With that done, we click on the view of the second tab and set it to be identified as a SegmentedTableViewController or type UITableViewController. We will create that class later in xCode. With that set we drag in a UITableView and connect its DataSource and Delegate methods to our view controller which has now been defined as SegmentedTableViewController. That is all we need to do in interface builder.

Going into xCode we do not need to modify any of the generated classes, however we do need to create a new one. Hit Apple + N and create a new UITableViewController called SegmentedTableViewController. This class will have the datasource methods for a UITableView all ready.

In this class we are going to need an int called selectedSegment, this will be updated to represent which segment is selected. Within the main we need to uncomment the viewDidLoad method and enter the following code.

This code gets the UISegmentedControl from the titleView of the navigationItem, and modifies it to add an action so that when the selected segment changes a method called segmentAction is called. The selectedSegment int is set to the initially selected segment and the titleView is reset with the modified UISegmentedControl.

Next we need to create the method which the UISegmentedControl will call. Here is the code for that method, following the same syntax as a IBAction Method.

Advertisement

This code takes the sender which will be out UISegmentedControl and gets the new selectedSegment from it and sets out variable to that value. Finally it tells the UITableView that something has happened and the data in the table needs to be reloaded.

The final steps is to tell the UITableView that is will be displaying 100 cells and telling the returned cell for each row to have some text which is a product of the selected segment. I chose to have each cell read “I AM CELL (selectedSegment * indexPath.row)”. This essentially means that when segment 0 is selected every cell will read.

I AM CELL 0

When segment 1 is selected the cells will read.

I AM CELL 0

I AM CELL 1

I AM CELL 2

….

When segment 2 is selected the cells will read.

I AM CELL 0

I AM CELL 2

I AM CELL 4

I AM CELL 6

….segment. I chose to

The code to make this happens is…

You can download the source for this tutorial here. icodesegmentcontrol

This entry was posted in Interface Builder, iPhone Programming Tutorials and tagged , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

46 Comments

  1. Peter
    Posted October 13, 2008 at 4:28 am | Permalink

    Nice tutorial.. thank you!

  2. MacE
    Posted October 13, 2008 at 7:18 am | Permalink

    No source??? It’s easier to follow when you have a xcode project source file to follow by.

  3. Jason
    Posted October 13, 2008 at 10:29 am | Permalink

    Ok, the tutorials on the site are great, but you need to stop putting screenshots of code up and put up the actual text. Very annoying.

  4. Posted October 13, 2008 at 11:46 am | Permalink

    Nice tutorial.

  5. Posted October 13, 2008 at 11:48 am | Permalink

    @MacE,

    Sorry about that. The source is now posted.

    @Jason,

    There is a reason for not putting the actual code in text. If people just copy and paste the text, it is much harder to learn what you are doing. I have gone through many tutorials where I just copied and pasted and didn’t get anything out of it.

    It’s like when you take notes for school. You can’t easily commit the stuff to memory without physically writing it down.

  6. Posted October 13, 2008 at 11:01 pm | Permalink

    Hello,

    I am new to iPhone programming, but I wonder if [segmentControl release]; is OK in viewDidLoad, since we did not actually create an object there, just obtained a pointer to an existing object.

  7. Posted October 13, 2008 at 11:49 pm | Permalink

    Hey Paul,

    You are correct, actually both the [segmentControl release] from –(void)viewDidLoad and -(void)segmentAction:(id)sender should be removed. Nice catch!

  8. David
    Posted October 14, 2008 at 12:21 am | Permalink

    Fully agreed. Actually typing in the code helps the mind retain.

    Thanks for the tutorial.

    One thing though… why are we releasing data that we only get a pointer to?

    For example…

    UISegmentedControl *segmentControl = sender;
    selectedSegment = [segmentControl selectedSegmentIndex];

    [segmentControl release]; // why do we need to do this? Does sender retain???

    Thanks! Keep the tutorials coming, they’re great!

  9. David
    Posted October 14, 2008 at 12:26 am | Permalink

    Ah, never mind my above comment. It was caught by Paul while I was writing my comments up.

  10. MacE
    Posted October 14, 2008 at 5:07 pm | Permalink

    @Brandon

    Thanks for posting the source. That helps me a lot! Thanks again. Nice Tut.

  11. Jazzgenx
    Posted October 15, 2008 at 6:17 pm | Permalink

    @Brandon

    DUDE…you dont know what u have done!!!!….. you are AWESOME!!!…i was having this problem since the past few days….and this tutorial was just what i needed….

    just a tiny feedback..”ask people to add the core graphics framework because xcode with it;s default config gives a GRectZero error..

    thanks Again

  12. jase
    Posted October 16, 2008 at 12:17 am | Permalink

    Great tutorial!

    Helped me a lot, but when I did this tutorial, after hitting the Number*2 button, the entire Segmented control would disappear. I had to comment out this line in order for it to remain visible.

    // [segmentControl release];

  13. Steve
    Posted October 16, 2008 at 4:58 am | Permalink

    Thank you very much. I’ve been looking high and low for a simple approach to this problem and this is by far the easiest to follow.

  14. Daniel
    Posted October 17, 2008 at 7:32 pm | Permalink

    I have three questions about viewDidLoad.

    First, why do we need this line:

    self.navigationItem.titleView = segmentControl;

    If segmentControl already points to the same object then why would you need to do this assignement. Arn’t they already equal? It seems like this won’t hurt anything, but do you need it? I pulled it out and everything seems to run fine, but I wanted to ask anyways.

    Second, people are saying that you do not need to release the segmentControl, as in:

    [segmentControl release];

    Coming from a C/C++ background it makes sense to me that you don’t need this; however, from what I am reading I am not sure that that is the case. I can definitly be mistaken, but isn’t the retainCount incremented with the statement:

    UISegmentedControl *segmentControl = …

    If so, then wouldn’t the release be needed? I’m just trying to understand the way the retainCount works in this instance.

    Third, what is the advantage of creating the selectedSegment class property. Why not simply ask the UISegmentedControl directly each time you need to know which segment is selected. Is there a significant runtime advantage in speed or something? Just wondering at what times I would or would not create these types of intermediate variables rather then talking directly to the objects in question (like the UISegmentedControl object).

    Thats it for me. Thanks for the help.

  15. Daniel
    Posted October 18, 2008 at 4:38 pm | Permalink

    Just to clarify my third question above. Why not get rid of selectedSegment and do something like this within the TableView function:

    UISegmentedControl *segmentControl = self.navigationItem.titleView;

    cell.text = [NSString stringWithFormat:@"I AM CELL %d", ([segmentControl selectedSegmentIndex] * indexPath.row)];

    Is it because this solution involves more runtime resources then simply tracking the selectedSegement in a class variable?

  16. Daniel
    Posted October 18, 2008 at 4:40 pm | Permalink

    Also, let me add a forth question. Can someone explain how to resolve the compiler warning for this line of code:

    UISegmentedControl *segmentControl = self.navigationItem.titleView;

    Normally code can be rewritten to eliminate warnings. Is there some way to do so in this case?

    Ok…that is it for me. Those 4 questions and I’m good to go. Thanks.

  17. Daniel
    Posted October 19, 2008 at 6:16 pm | Permalink

    I figured out question number 4. I think that it is a problem of type casting (so to speak). If you do the following it will cast the types properly.

    UISegmentedControl *segmentControl = (UISegmentedControl *) self.navigationItem.titleView;

    So, any ideas on the other three questions?

  18. Daniel
    Posted October 19, 2008 at 6:24 pm | Permalink

    And for my third question. You can get rid of selectedSegment all together and just put this line into tableView instead:

    cell.text = [NSString stringWithFormat:@"I AM CELL %d", ([(UISegmentedControl *) self.navigationItem.titleView selectedSegmentIndex] * indexPath.row)];

    Since the UISegmentedControl already exists then there shouldn’t be any runtime advantages for memory usage, and since we are just dealing with pointers then this should also be comparable in runtime speed (though maybe there is some small referencing degradation).

    So, I am still not sure whether there is any advantage or disadvantage of one approach over the other. But this single line seems to make things easier for me to follow then having that extra variable declared in my class (selectedSegment).

    Any thoughts on the subject? Anyone? Maybe I should be posting this in the forums.

  19. Posted October 20, 2008 at 11:27 am | Permalink

    @Daniel,

    I’m not sure why the author of this tutorial hasn’t responded to your questions. I will email him later today and let him know…

  20. Posted October 20, 2008 at 3:29 pm | Permalink

    @Daniel,

    Hey sorry about the long response time. Wow lots of questions. I simply chose to code it the way I coded it, the [segmentControl release] statements should be removed as I stated earlier, and as for your more optimized code, I believe that should work as well, this essentially brings us into the topic of hope flexible Objective C can be when you get into it. It is really up to the programmer. Thanks for your interest and keep on coming back to iCodeBlog!

  21. Daniel
    Posted October 21, 2008 at 6:58 pm | Permalink

    Cool, but could you confirm for me that the assignment was not needed (question 1). I just don’t want to assume that it is not needed if there is actual a reason for it. Was this line needed in viewDidLoad?

    self.navigationItem.titleView = segmentControl;

    I think that that is the only question that I have not confirmed. If I pull it out it does run properly, and I think it is not needed, but I just want to confirm that that is the case. Maybe there is something going on with that line that I do not understand and I don’t want to miss anything. Thanks.

  22. cjr
    Posted November 13, 2008 at 4:23 pm | Permalink

    Hi,

    Really useful tutorials. I think you mentioned in an early tutorial that you weren’t completely happy with your iPhone simulator screenshots. Here is a tip from David Pogue’s Mac OSX Missing Manual:

    Press Shift-Apple-4
    Hover over iPhone simulator window
    Press the Space Bar
    Press the mouse button

    The screenshot will appear on your desktop.

  23. Posted November 15, 2008 at 1:01 pm | Permalink

    @cjr

    Sweet thanks for the tip!

  24. N
    Posted November 21, 2008 at 1:33 pm | Permalink

    “I simply chose to code it the way I coded it”, so uh, I guess you don’t know the answer.

  25. Tom
    Posted December 3, 2008 at 2:12 pm | Permalink

    Collin, thanks for the really useful tutorial.

    I found that compile warning annoying so I looked for a different way to get this to work.

    Made the following changes to the code:
    1) Added an IBOutlet for the segmented control
    2) Converted the segmentAction method to an IBAction
    3) Commented out the viewDidLoad method. the segmented control starts with segment 0 selected by default.
    3) Made the necessary connections in IB: Connected the segmented control to the segCtrl outlet in the TableViewController. Connected the valueChanged event in the segmented control to the segmentAction in TableViewController.

    I think this is cleaner but, as you say, there’re always several ways to implement something. Not to mention the fact that it’s always easy to tinker with code that someone else got working first.

    Thanks, again, for putting this together and publishing it. Saved me a lot of time.

    Here are the relevant code fragments:

    @interface SegmentedTableViewController : UITableViewController
    {
    int selectedSegment;
    UISegmentedControl *segCtrl;
    }

    @property (nonatomic, retain) IBOutlet UISegmentedControl *segCtrl;

    - (IBAction) segmentAction:(id)sender;

    @end

    ———————————————————–

    @implementation SegmentedTableViewController
    @synthesize segCtrl;

    // – (void)viewDidLoad //Not necessary, I think.

    -(IBAction)segmentAction:(id)sender
    {
    selectedSegment = [self.segCtrl selectedSegmentIndex];
    [self.tableView reloadData];
    }

  26. Posted December 18, 2008 at 8:32 am | Permalink

    Great tutorial but you should rerecord it without the “HUH” “HUM” that you interject between every few words.

  27. Tylor
    Posted January 2, 2009 at 9:57 am | Permalink

    Thanks! Great tutorial. I liked the video a lot. It was a bit fast and I wouldn’t have gotten it hadn’t I already known a little bit about Xcode. But luckily I was able to follow along. Keep up the great work!

  28. Posted January 14, 2009 at 3:44 pm | Permalink

    Tom,

    That worked great. I also took out both
    int selectedSegment
    and
    UISegmentedControl *segCtrl, including any references in the code to these variables in the implementation file.
    (like @property, @sythesize, and the segmentAction method)

    All we need is the following two lines in the cellForRowAtIndexPath method.

    UISegmentedControl *segmentControl = (UISegmentedControl *)self.navigationItem.titleView;
    cell.text = [NSString stringWithFormat:@"I am cell %d", ([segmentControl selectedSegmentIndex] * indexPath.row)];

  29. Craig
    Posted January 15, 2009 at 1:37 pm | Permalink

    Great tutorials… much appreciated.

    Just wondering if anyone else has experienced strange behavior on the iPhone simulator. It seems to work fine for the first few clicks but then on the second screen (where you can switch between the cell numbers) the top buttons disappear and it stops functioning after you click a few times.

    Running Simulator version Version 2.2 (77.4.9) and code is unmodified from what was posted.

    thanks, -cb

  30. Posted January 16, 2009 at 10:43 am | Permalink

    Craig,

    Yeah, the author posted that you should take out the [segmentControl release] messages. It should work after you do that.

  31. Rob
    Posted January 30, 2009 at 7:39 pm | Permalink

    Please remove [... release] from code
    You are confusing hell out of beginner obj-c programmers

  32. David
    Posted February 22, 2009 at 12:10 pm | Permalink

    Thank you for the help!

  33. scrudrv
    Posted March 19, 2009 at 7:22 am | Permalink

    Thanks for this tutorial, however this one is better to read then to listen.

  34. Vijayant Bhatnagar
    Posted March 22, 2009 at 3:26 am | Permalink

    How can we have hierarchical tableviews on top of tab bar view ? Can you post some tutorial for ipod like application ?

    Thanks,
    Vijayant Bhatnagar

  35. Posted April 7, 2009 at 6:09 am | Permalink

    I’m not sure if the UISegmentedControl issue blanking out after a couple of selections has been resolved.

    I had to comment out both occurrences of
    [segmentControl release];

    in order for it keep working. I tested it in Performance Tool and didn’t see any memory leak so perhaps it’s of no consequences but, being as a beginner, I would really like to know if we can get away with this in future applications.

    The tutorial is definitely worth doing and is very helpful. However, you need to be more specific about the actions you take, for example instead of saying “we’re going to set its data source and delegate to that segmentedTableViewControl” say “right click on the view and then drag from the dataSource circle to the view and from the delegate circle to the view.”

    Brandon’s tutorials are great in this regard in that they clearly show what actions he’s taking and you don’t have to guess.

    Cheers
    Roland Combes

  36. Posted July 9, 2009 at 6:30 am | Permalink

    What time was the train? Did you make it?

    You went through this far too fast. I have no idea if this is a good tutorial or not because I can’t follow it.

    It is a shame because you have obviously spent alot of time (editing the screen capture, working out what you want to show, learning it in the first place), money (screen capture software ) and effort. But the end product is just unwatchable.

    Deep breath, slow down.

  37. Satyam
    Posted July 22, 2009 at 6:14 am | Permalink

    Hi, After adding class name to view as “SegmentedViewController”, I added a UITableView. On right click and assigning the delegate and datasource, I am not able to select “SegmentedViewController”. Its alsways pointing to “View”. Why? How can I resolve the problem? I am using XCode 3.0

  38. James
    Posted August 27, 2009 at 8:46 am | Permalink

    If I change the cells to show a string instead of your numbers it just throws EXC_BAD_ACCESS. Does anyone know why? I’ve declared the string just as the int is declared and am calling it in the string as %@ instead of %d.

    Thanks

  39. Daniel B
    Posted August 31, 2009 at 1:44 pm | Permalink

    For some reason, when I run the program, I can’t click the second tab. I couldn’t find any steps that I missed… I messed around with it for a while trying to fix it, but with no success. Anyone have any ideas what I did wrong?

  40. restfulsilence
    Posted October 4, 2009 at 6:04 am | Permalink

    I found a little Bug. When you switch to the “Second” View and then to “Numbers” then to “Numbers*2″ (which immediately disappear) and then again back to “First” View. The program crashed.

    This is one of some scenarios.

  41. Posted October 8, 2009 at 7:41 pm | Permalink

    I am here again, Been waiting an hour and video wont load.

  42. Posted October 8, 2009 at 8:19 pm | Permalink

    Downloaded the sample, it crashes if you tap on too much.

  43. AJ
    Posted October 13, 2009 at 6:15 am | Permalink

    Hey,

    I’ve followed the tutorial and get an unhandled exception. Just to check that it wasn’t me being silly I downloaded the code and get the same unhandled exception!

    AJ

  44. Robert
    Posted October 21, 2009 at 12:50 am | Permalink

    I have the exact same problem as Satyam, could not assign the UITableview to the SegmentedTableViewController. Using XCode 3.1.4. Any other ways to define the datasource and delegate?

  45. Posted November 9, 2009 at 2:35 pm | Permalink

    Hi.
    First, great site.
    second, how do I/we combine this tutorial with the hello world app.
    One or more hello world at each “tab”?
    I can’t figure out how to combine these tutorials.

  46. kctan
    Posted December 31, 2009 at 11:10 pm | Permalink

    The video is not loading. What is the possible problem?
    I have no problem with the video for the UITabbar tutorial.

One Trackback

  1. By iCodeBlog » Blog Archive » Hello Everyone on May 8, 2009 at 2:17 pm

    [...] for varying studies around the university. Long time readers may remember a post I did back in October of last year. I was still fairly new to the SDK then and now have the skills required to make many [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">