сохранение состояния программы iPhone с глубоким UINavigationController - PullRequest
3 голосов
/ 28 февраля 2010

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

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

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

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

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

спасибо!

Ответы [ 4 ]

1 голос
/ 12 марта 2010

Вот что я в итоге решил.

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

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

1 голос
/ 07 июля 2010

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

- (void)applicationDidBecomeActive:(UIApplication*)application{</p> <pre><code> 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"];
 }
</code>
0 голосов
/ 31 декабря 2012

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

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

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 голосов
/ 28 февраля 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...