сохранение состояния программы iPhone с помощью глубокого UINavigationController

Может ли кто-нибудь поделиться хорошим способом сохранить состояние программы (стек UINavigationController и т. Д.) Приложения iPhone.

Мое приложение получает кучу информации из сети, и я хочу вернуть человека обратно на последний экран, на котором он был, даже если он был на 3 или 4 экрана.

Я предполагаю, что мне нужно будет перезагружать данные из сети по мере того, как я воссоздаю контроллеры UINavigation. У меня не обязательно проблемы с этим.

Я думаю о том, что, возможно, мои объекты UINavigationController реализуют какой-либо протокол, который позволяет мне сохранять / устанавливать их состояние? Я хочу услышать мнение других, кому, возможно, потребовалось реализовать аналогичный сценарий, и узнать, как они этого добились.

В моем приложении есть UITabbarController в корне и элементы UINavigationController для каждого элемента панели вкладок.

Благодарность!


person jr.    schedule 28.02.2010    source источник


Ответы (4)


Вот что я сделал в качестве решения.

Я создал протокол, который содержит метод для «получения состояния», а затем для «инициализации с состоянием из метода словаря».

Итак, когда приложение закрывается, я просматриваю все свои контроллеры и запрашиваю у них состояние. И затем, когда приложение запускается, я выполняю инициализацию с состоянием, передавая словарь, который я сериализовал. Это работает хорошо!

person jr.    schedule 12.03.2010

Чтобы сохранить и перезагрузить стек навигации, я сделал следующее.

- (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:(UIApplication *)application {

// 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"];
 }
person JRo    schedule 06.07.2010
comment
Вы уверены, что это жизнеспособный подход? Кажется, что вы храните UIViewControllers в NSUserDefaults. Насколько мне известно, в NSUserDefaults можно хранить только объекты .plist. Кроме того, это может быть намного сложнее для других приложений, в которых также необходимо сохранять и извлекать переменные. На мой взгляд, лучший вариант - работать с NSDictionary (хранящимся в NSUserDefaults). - person Bart Jacobs; 15.09.2010

Я сделал это в одном из своих приложений, и, насколько я могу судить, это довольно простой процесс.

Для каждого из ваших TargetViewController вам нужно будет нажать их на контроллер представления, установить для анимации значение NO, чтобы казалось, что он восстанавливает состояние.

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

Может быть, кто-то еще может указать вам на фреймворк, который позволит вам сохранить эти контроллеры представления.

person John Ballinger    schedule 28.02.2010

Думаю, я использую (вроде) тот же подход, что и младший. Я отправлю ее ей в образовательных целях.

У меня есть протокол, который выглядит так:

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;
    }

}
person Wolfgang Schreurs    schedule 31.12.2012