如何在深入 UITableViewController 结构中恢复用户位置?

发布于 2024-08-20 11:42:03 字数 330 浏览 14 评论 0原文

我有一个 CoreData 模型,其中包含级别,该级别可以再次包含子级别。

我用列出所有子级别的 UITableViewController 来表示每个级别。当用户点击一行时,新的 UITableViewController 会被推送到 navigationController 上。这里没问题。

我将如何在此表结构中存储用户位置。有这样做的最佳实践吗?如果结构的深度已知,那么我这样做没有问题,但不知何故困惑如何以未定义的深度来处理这个问题。

我应该将用户点击的 NSIndexPath 存储到数组中并将其写入磁盘吗?

I have a CoreData model that contains Levels which can again contain childLevels.

I represent each level with a UITableViewController listing all childLevels. When a user taps a row a new UITableViewController is pushed onto the navigationController. No problem here.

How would I go about storing the user location within this table structure. Is there a best practice for doing this? I have no problem doing this if the depth of the structure was known, but somehow puzzled how to approach this with a undefined depth.

Should I store the NSIndexPath tapped by the user into an array and write it to disk?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

罪歌 2024-08-27 11:42:03

使用 NSIndexPath 作为您的状态并保存/恢复它以实现持久性对我来说很有意义。

另外,您的方法(使用存储为属性列表(plist)的 NSArray)应该相当简单。

Using an NSIndexPath for your state and saving/restoring it for persistence makes sense to me.

Also your approach--to use an NSArray stored as a property list (plist)--should be fairly straightforward.

や三分注定 2024-08-27 11:42:03

我没有使用用户点击的 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;

}

Instead of using the NSIndexPaths tapped by the user I went with the underlying NSManagedObjects which is a lot safer (in case number or sorting of objects change) and faster (because I do not need the whole fetchRequest and or view).

I subclassed the UINavigationController and did the following.

When pushing a new TableViewController for a level (stored in parentLevel) I append this to an array in 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];

   }
}

When I pop a viewController I simply remove the last entry from that array:

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

I can then use this array when initializing the NavigationController when the app is next started to rebuild the tree:

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

}
握住你手 2024-08-27 11:42:03

我正准备开始为我自己的应用程序执行此操作,这是计划。每次 UIViewController 加载新视图时,它都会在 NSUserDefaults 中创建一个值,该值提供有关该新视图的信息(从何处打开它、填充了哪些数据等)。当子视图返回时,视图控制器清除该值。当 UIViewController 进行初始加载时,它会检查默认值以查看之前是否存储了值,如果是,则会采取适当的操作来重新加载该子视图。该过程沿着导航链继续进行。

我这样做而不是 NSIndexPath 的原因是,除了主视图层次结构之外,我还有一堆辅助视图(添加、删除、编辑等)。我不仅需要记录主导航之外存在的这些视图的打开,而且它们还需要保存许多状态详细信息(选定的选项、部分输入的文本等)。

我会回来的如果结果证明这是一个糟糕的计划,请投反对票。

I'm just about ready to start doing this for my own app and here's the plan. Each time a UIViewController loads a new view it will create a value in the NSUserDefaults that gives information on that new view (where it was opened from, what data it's populated with, etc). When the subview returns the view controller clears out this value. When the UIViewController has it's initial load it checks the defaults to see if it previously stored a value, if so, it takes the appropriate action to reload that subview. The process continues down the navigation chain.

The reason I've done this instead of an NSIndexPath is because, in addition to the main view hierarchy, I've got a bunch of auxiliary views (add, remove, edit, etc.). Not only will I need to record the opening of these views that exist outside of the main navigation, but they will have a lot of state details they need to save too (selected options, partially entered text, etc.)

I'll come back here and downvote this if it turns out to be a shit plan.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文