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
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.
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







47 Comments
Nice tutorial.. thank you!
No source??? It’s easier to follow when you have a xcode project source file to follow by.
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.
Nice tutorial.
@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.
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.
Hey Paul,
You are correct, actually both the [segmentControl release] from –(void)viewDidLoad and -(void)segmentAction:(id)sender should be removed. Nice catch!
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!
Ah, never mind my above comment. It was caught by Paul while I was writing my comments up.
@Brandon
Thanks for posting the source. That helps me a lot! Thanks again. Nice Tut.
@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
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];
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.
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.
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?
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.
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?
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.
@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…
@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!
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.
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.
@cjr
Sweet thanks for the tip!
“I simply chose to code it the way I coded it”, so uh, I guess you don’t know the answer.
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];
}
Great tutorial but you should rerecord it without the “HUH” “HUM” that you interject between every few words.
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!
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)];
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
Craig,
Yeah, the author posted that you should take out the [segmentControl release] messages. It should work after you do that.
Please remove [... release] from code
You are confusing hell out of beginner obj-c programmers
Thank you for the help!
Thanks for this tutorial, however this one is better to read then to listen.
How can we have hierarchical tableviews on top of tab bar view ? Can you post some tutorial for ipod like application ?
Thanks,
Vijayant Bhatnagar
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
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.
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
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
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?
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.
I am here again, Been waiting an hour and video wont load.
Downloaded the sample, it crashes if you tap on too much.
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
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?
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.
The video is not loading. What is the possible problem?
I have no problem with the video for the UITabbar tutorial.
I want to put images instead of text in the segmented controller. In the interface builder it doesn’t have a list of images in the dropdown for the images. Where would I put the images that I could select from?
One Trackback
[...] 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 [...]