views:

1111

answers:

3

I have an application that has a UITabBarController with two tabs, each having its own navigation controller. Now I want to store the state of the application when the user closes it, so that when the user relauches the application will show the same place as the last time before it was closed.
So, in applicationWillTerminate: I have

[NSKeyedArchiver archiveRootObject:tabBarController toFile:@"lastVisitedTab"];

Then, in applicationDidFinishLaunching: I have

UITabBarController *last= (UITabBarController *)[NSKeyedUnarchiver unarchiveObjectWithFile:@"lastVisitedTab"];
if (last)
    tabBarController = [last retain];

I also have an extension to UIImage to make it compliant to NSCoding. However, this doesn't work, as the state is not preserved. The first tab gets selected all the time, and no navigation is preserved either.
Can someone tell me what's wrong, or show me how to do it correctly?

+3  A: 

I think it's overkill to persist the actual objects. Instead, just save the selectedIndex property (use [NSNumber numberWithInt: tabBar.selectedIndex]) and then read it back and set the property on launch. Maybe this doesn't properly answer your question, but it might be sufficient for what you are trying to achieve.

Felixyz
actually that's what i'm thinking now, but the tables have dynamic contents so i can't just store the index :(maybe the url will do the trick
phunehehe
What tables? If you are using UITableViews, it also makes much more sense to persist the **data** rather than the views themselves.
Felixyz
the data itself is dynamic, so cannot store thatanyway thank you very much for giving me the ideai also put my code below
phunehehe
+2  A: 

I figured out how to do it finally, thanks to Felixyz's idea. Below is what I have to do to store tabs, regardless of their data. If, says, a view is loaded with data downloaded from an URL, store the URL instead of the whole view. You would have to override

- (void)encodeWithCoder:(NSCoder *)encoder
- (id)initWithCoder:(NSCoder *)decoder

in your UIViewController subclass to tell the view controller to save appropriate data before the application stops.
Now in your application delegate save the data before quiting

- (void)applicationWillTerminate:(UIApplication *)application
    // data buffer for archiving
    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    // the index of selected tab
    [archiver encodeInt:tabBarController.selectedIndex forKey:@"TAB_INDEX"];
    // array of keys for each navigation controller, here I have 3 navigation controllers
    NSArray *keys = [NSArray arrayWithObjects:
                     @"NAVIGATION_CONTROLLER_1",
                     @"NAVIGATION_CONTROLLER_2",
                     @"NAVIGATION_CONTROLLER_3", nil];
    for (int i = 0; i < keys.count; i++) {
        UINavigationController *controller = [tabBarController.viewControllers objectAtIndex:i];
        NSMutableArray *subControllers = [NSMutableArray arrayWithArray:controller.viewControllers];
        // the first view controller would already be on the view controller stack and should be removed
        [subControllers removeObjectAtIndex:0];
        // for each of the navigation controllers save its view controllers, except for the first one (root)
        [archiver encodeObject:subControllers forKey:[keys objectAtIndex:i]];
    }
    [archiver finishEncoding];
    // write that out to file
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    [data writeToFile:[documentsDirectory stringByAppendingPathComponent:@"ARCHIVE_PATH"] atomically:YES];
}

And then, when relaunching

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // set up the tabs
    tabBarController = [[UITabBarController alloc] init];
    tabBarController.viewControllers = [NSArray arrayWithObjects:
                                        [[[UINavigationController alloc] initWithRootViewController:rootViewController1] autorelease],
                                        [[[UINavigationController alloc] initWithRootViewController:rootViewController2] autorelease],
                                        [[[UINavigationController alloc] initWithRootViewController:rootViewController3] autorelease], nil];
    // look for saved data, if any
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSData *archive = [NSData dataWithContentsOfFile:[documentsDirectory stringByAppendingPathComponent:@"ARCHIVE_PATH"]];
    // if no data found, skip this step
    if (archive) {
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:archive];
        // set the tab
        tabBarController.selectedIndex = [unarchiver decodeIntForKey:@"TAB_INDEX"];
        NSArray *keys = [NSArray arrayWithObjects:
                         @"NAVIGATION_CONTROLLER_1",
                         @"NAVIGATION_CONTROLLER_2",
                         @"NAVIGATION_CONTROLLER_3", nil];
        // push view controllers up the stack
        for (int i = 0; i < keys.count; i++) {
            NSArray *controllers = [unarchiver decodeObjectForKey:[keys objectAtIndex:i]];
            for (UIViewController *controller in controllers) {
                [((UINavigationController *)[tabBarController.viewControllers objectAtIndex:i]) pushViewController:controller animated:NO];
            }
        }
    }
    // Add the tab bar controller's current view as a subview of the window
    [window addSubview:tabBarController.view];
}
phunehehe
A: 

i try it but the result is exceptions its not working

Qasim Shah