Saturday, September 5, 2009

Saving Tabs

I've been so ranty lately that I thought I should take a short break from writing More iPhone 3 Development to put up something technical. This is a relatively beginner-level tutorial, but it's one of those little features we take for granted but really hate when it's not there (at least I do).

I'm talking about saving the selected tab. When you start Apple's Clock application, for example, it always takes you to the tab you were on when you last used it. In most cases, this is a very good idea. There may be cases where a specific tab should have preference, but generally, you should bring the user back where they left off.

If you're using a tab bar controller, it's relatively simple to implement this. In viewDidLoad or applicationDidFinishLaunching:, you need to do something like this:

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger whichTab = [defaults integerForKey:kSelectedTabDefaultsKey];
tabBarController.selectedIndex = whichTab;

Then, either when the selection changes, or when the application quits, you have to store off the tab in the preferences so it'll be there next time. I prefer doing it whenever the tab selection changes because then we've captured it, even if there's a crash or phone call, but doing it when the application finishes is fine for most purposes. Here's how you reverse the process:

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger whichTab = tabBarController.selectedIndex;
[defaults setInteger:whichTab forKey:kSelectedTabDefaultsKey];

But what if you're just using a UITabBar and not a UITabBarController? That's a touch more difficult because tab bars don't work by indices. It's relatively easy to add the exact same functionality that's on the tab bar controller to the tab bar by using a category, however:

UITabBar-Index.h
#import <Foundation/Foundation.h>

@interface UITabBar(Index)
- (NSUInteger)selectedIndex;
- (void)setSelectedIndex:(NSUInteger)newIndex;
@end



UITabBar-Index.m
#import "UITabBar-Index.h"

@implementation UITabBar(Index)
- (NSUInteger)selectedIndex {
return [self.items indexOfObject:self.selectedItem];
}

- (void)setSelectedIndex:(NSUInteger)newIndex {
self.selectedItem = [self.items objectAtIndex:newIndex];
}

@end


Once you have that, you can import this category and use the exact same code from above on the tab bar rather than the tab bar controller.

Here's an example project. It includes a functioning tab bar application that saves the tab position, and also contains the category above.



7 comments:

Nick said...

dude, you are a tits programmer. I love your blog and book.

joshm said...

Keep in mind that when you add or rearrange tabs to new versions of your application the indices will change. I prefer to use names instead of indices when saving things like this so I don't have to worry about that.

Jeff LaMarche said...

Joshm:

That's a good point, and that's another way you can approach it.

However it can go both ways. Names can be changed during development and they can be localized. If you provide an update to your app with a new localized nib, for example, when you provide a new localization, the saved tab name won't match what's saved in defaults for anyone using the language for which you provided the new localization. It can be problematic also for multi-lingual people who change their locale periodically because every time they change locale, some or all tabs may change.

With most UI elements, the best choice would be to use the element's tag to store it, but since Apple created UIBarButton as a subclass of NSObject instead of UIView or UIControl, we don't have that option, meaning any solution is potentially problematic when you add, reorder, or delete tags.

When in doubt, I usually look to what Apple has done. Since they used indices in UITabViewController, I stick with indices, but as with almost anything, there's no one right way to do it. If using the name is working for you, that's cool. If you have no plans to localize your app, then your solution might actually be the best one.

Fortunately, whether you use name or index, the situations where there will be problems are going to happen rarely enough that it probably won't even be noticed.

The Lion Arch Dev Team said...

I have an app I'm working on that has 7 tabs with a webView for each. When I edit and rearrange the tabs and then relaunch the app the tabs are back to their original places. If you look at the iTunes native app on the iPhone it has the same thing, but when you edit the tab locations there they stay where you want them to. I'm sure it's a simple fix, but I'm missing it. Can you help me, please?

Edwin said...

scrub m65 kamagra attorney lawyer body scrub field jacket lovegra marijuana attorney injury lawyer

JeansPilot said...

JeansPilot offers the chance to buy a large variety of men’s and women’s jeans clothing from the world famous Italian Brands.
Online jeans clothing store looks for original fashion clothing sales and clearances of worldwide known designers. We participate in fashion auctions to get the lowest possible price for Top quality Clothes, Shoes and Accessories.
Buy Jeans

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels