Saving iPhone program state with deep UINavigationController

Can anyone share a good way to save the state of the program (the UINavigationController stack, etc.) of the iPhone application.

My application receives a lot of information from the network, and I want to return the person to the last screen on which they were, even if it was 3 or 4 screens.

I assume that I will need to reload data from the network along the way when I recreate the UINavigation controllers. I have no problem with this.

I think that maybe my UINavigationController objects implement some type of protocol that allows me to save / set their state? I am looking to hear from others who may have needed to implement a similar scenario and how they did it.

My application has a UITabbarController in the root elements and a UINavigationController for each tab bar item.

thank!

+3
source share
4 answers

Here is what I did as a solution.

I created a protocol that contains the "get state" method, and then "init with state from the dictionary method".

So, when the application closes, I look through all my controllers and request their status. And then, when the application starts backing up, I initialize with the state, passing in the dictionary I'm serialized. It works well!

+1
source

To save and reload the navigation stack, I did the following.

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

    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];

// if a navigation stack is stored in UserDefaults
// loop through the array until all views are pushed onto the stack.
// This will bring the user to the view they were on when the app terminated.
if([prefs objectForKey:@"viewStack"] != nil){
    for (id viewItem in [prefs arrayForKey:@"viewStack"]) {
        [self.navigationController pushViewController:viewItem animated:NO];
    }
 }
}

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

// Create an array to store the array of viewControllers currently on the stack.
NSArray *stackArray = [NSArray arrayWithArray:navigationController.viewControllers];

// if user has navigated beyond the rootview, save the nav stack.
if([stackArray count] > 1)
    [[NSUserDefaults standardUserDefaults] setObject:stackArray forKey:@"viewStack"];
 }
+1

,

TargetViewControllers , NO, .

[[self navigationController] pushViewController:targetViewController animated:NO];

, - , .

0

, () , . .

, :

FSViewControllerRestoration.h

#import <Foundation/Foundation.h>


@protocol FSViewControllerStateRestoration <NSObject>

@required;
- (NSDictionary *)currentState;
- (void)restoreState:(NSDictionary *)state;

@end

, . , , , restoreState:.

FSViewControllerStorage.h

#import <Foundation/Foundation.h>
#import "FSViewControllerStateRestoration.h"


@interface FSViewControllerStateStorage : NSObject

+ (BOOL)storeViewControllerStack:(NSArray *)stack;
+ (NSArray *)loadViewControllerStack;

@end

FSViewControllerStorage.m

#import "FSViewControllerStateStorage.h"


#define FS_PATH_APPLICATION_STATE_FILE [FS_PATH_DOCUMENTS_DIR stringByAppendingPathComponent:@"appstate.dat"]


@implementation FSViewControllerStateStorage

+ (BOOL)storeViewControllerStack:(NSArray *)stack
{
    DLog(@"storing view controller stack ...");

    if (stack.count <= 1)
    {
        return [NSKeyedArchiver archiveRootObject:nil toFile:FS_PATH_APPLICATION_STATE_FILE];
    }

    NSArray *items = @[];

    for (UIViewController *viewController in stack)
    {
        NSString *className = NSStringFromClass(viewController.class);
        NSDictionary *state = @{};

        if ([viewController conformsToProtocol:@protocol(FSViewControllerStateRestoration)])
        {
            state = [(id <FSViewControllerStateRestoration>)viewController currentState];
        }

        items = [items arrayByAddingObject:@{@"Class" : className, @"State" : state}];
    }

    return [NSKeyedArchiver archiveRootObject:items toFile:FS_PATH_APPLICATION_STATE_FILE];
}

+ (NSArray *)loadViewControllerStack
{
    DLog(@"loading view controller stack ...");

    NSArray *items = [NSKeyedUnarchiver unarchiveObjectWithFile:FS_PATH_APPLICATION_STATE_FILE];
    NSArray *stack = @[];

    for (NSDictionary *dictionary in items)
    {
        NSString *className = [dictionary objectForKey:@"Class"];
        NSDictionary *state = [dictionary objectForKey:@"State"];

        Class class = NSClassFromString(className);
        UIViewController *viewController = [[class alloc] init];
        if ([viewController conformsToProtocol:@protocol(FSViewControllerStateRestoration)])
        {
            [(id <FSViewControllerStateRestoration>)viewController restoreState:state];
        }

        stack = [stack arrayByAddingObject:viewController];
    }

    return stack;
}

@end

AppDelegate ...

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [FSViewControllerStateStorage storeViewControllerStack:self.navigationController.viewControllers];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSArray *viewControllers = [FSViewControllerStateStorage loadViewControllerStack];
    if (viewControllers.count > 0)
    {
        self.navigationController.viewControllers = viewControllers;
    }
}

, , viewController, :

#pragma mark - View controller state restoration

- (NSDictionary *)currentState
{
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

    if (_newsItem)
    {
        [dictionary setObject:_newsItem forKey:@"NewsItem"];
    }

    if (_comments)
    {
        [dictionary setObject:_comments forKey:@"Comments"];
    }

    return dictionary;
}

- (void)restoreState:(NSDictionary *)state
{
    FSNewsItem *newsItem = [state objectForKey:@"NewsItem"];
    if (newsItem)
    {
        self.newsItem = newsItem;
    }

    NSArray *comments = [state objectForKey:@"Comments"];
    if (comments)
    {
        self.comments = comments;
    }

}
0

Source: https://habr.com/ru/post/1734730/


All Articles