Как восстановить местоположение пользователя в детализированной структуре UITableViewController?

StackOverflow https://stackoverflow.com/questions/2203393

Вопрос

У меня есть модель CoreData, содержащая уровни, которые снова могут содержать дочерние уровни.

Я представляю каждый уровень с помощью UITableViewController список всех дочерних уровней.Когда пользователь нажимает на строку, создается новая UITableViewController наталкивается на navigationController.Здесь нет проблем.

Как мне сохранить местоположение пользователя в этой структуре таблицы?Есть ли передовая практика для этого?У меня нет проблем сделать это, если была известна глубина конструкции, но я почему-то озадачился, как подойти к этому с неопределенной глубиной.

Должен ли я хранить NSIndexPath вставлен пользователем в массив и записывает его на диск?

Это было полезно?

Решение 2

Вместо использования NSIndexPaths, выбранных пользователем, я использовал базовый NSManagedObjects, который намного безопаснее (в случае изменения количества или сортировки объектов) и быстрее (потому что мне не нужен весь fetchRequest и/или представление).

Я создал подкласс UINavigationController и сделал следующее.

При отправке нового TableViewController для уровня (хранящегося в parentLevel) Я добавляю это в массив в UserDefaults:

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
   [super pushViewController:viewController animated:animated];

   if([viewController isKindOfClass:[LevelTableViewController class]]){
       NSMutableArray *array = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:LevelTablesPersistentKey]];
       NSManagedObject *obj = [(LevelTableViewController*)viewController parentLevel];

       if(obj!=nil){
         [array addObject:[[obj objectID].URIRepresentation absoluteString]];
       } 

       [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithArray:array] objectForKey:LevelTablesPersistentKey];

   }
}

Когда я открываю viewController, я просто удаляю последнюю запись из этого массива:

- (UIViewController *) popViewControllerAnimated:(BOOL)animated{
  UIViewController *vc = [super popViewControllerAnimated:animated];
  // remove last object
  if([vc isKindOfClass:[LevelTableViewController class]]){
     NSMutableArray *array = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:LevelTablesPersistentKey]];
     [array removeLastObject];
     [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithArray:array] objectForKey:LevelTablesPersistentKey];
  }

  return vc;
}

Затем я могу использовать этот массив при инициализации NavigationController при следующем запуске приложения для восстановления дерева:

- (LevelNavigationController*) initWithRootViewController:(LevelTableViewController*)vc {
if(self = [super initWithRootViewController:vc]){
    // Recreate structure from UserDefaults
    NSArray *array = [NSArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:LevelTablesPersistentKey]];
    [[NSUserDefaults standardUserDefaults] setObject:nil forKey:LevelTablesPersistentKey]; // set the array to nil -> will be rebuild when pushing viewcontrollers onto navigation stack

    NSPersistentStoreCoordinator *persistentStoreCoordinator = ...; // pointer to coordinator 
            NSManagedObjectContext * managedObjectContext = ...; // pointer to your context
    for (NSString *objId in array) {
        NSManagedObjectID *mobjId=[persistentStoreCoordinator managedObjectIDForURIRepresentation:[NSURL URLWithString:objId]];
        if(mobjId!=nil){

            NSManagedObject *obj = nil;
            NSError **err = nil;
            obj = [managedObjectContext objectWithID:mobjId];

            if(err==nil && obj){
                if([obj.entity.name isEqualToString:@"Level"]){
                    // push level

                    LevelTableViewController *nextLevel = [[LevelTableViewController alloc] initWithStyle:UITableViewStylePlain];
                    nextLevel.parentLevel = (Level*)obj;
                    [self pushViewController:nextLevel animated:NO];
                    [nextLevel release];
                } 
            } 
        }
    }

}

return self;

}

Другие советы

Используя NSIndexPath для вашего состояния и его сохранение/восстановление для устойчивости имеет для меня смысл.

Кроме того, ваш подход — использовать NSArray, хранящийся в виде списка свойств (plist), — должен быть довольно простым.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top