【问题标题】:SWRevealViewControllerSegue, reusing ViewcontrollersSWRevealViewControllerSegue,重用 Viewcontrollers
【发布时间】:2013-11-07 01:28:16
【问题描述】:

我正在使用 SWRevealViewController,并且我正在使用自定义 segue,我注意到每次执行 segue 时 SWRevealViewController 都会创建目标控制器的全新实例,有没有办法让 SWRevealViewController 重用视图控制器?

【问题讨论】:

  • Segues 总是实例化新的控制器,所以你不能重用它们。我不熟悉 SWRevealViewController,但如果您可以在代码中推送或呈现控制器而不是使用 segue,那就是您需要做的。
  • 嗨@rdelmar,你给了有趣的评论,我有一个后续问题:如果segues总是实例化新的控制器,不使用它们并总是尝试通过代码推送或呈现是否合乎逻辑?就像一般做法一样。
  • 不一定。很多时候,当您使用控制器时,您希望实例化一个新控制器,并在您返回时释放它(通过弹出、关闭或使用 unwind segue)。是否使用它们在很大程度上取决于您应用的工作流程。

标签: ios objective-c uiviewcontroller


【解决方案1】:

重用视图控制器的实例实际上非常简单,并且不需要修改 SWRevealViewController。

在您指定的 MenuViewController(当您希望显示菜单项的视图控制器时负责调用 segue 的视图控制器)中,创建视图控制器缓存。这将用于在通过 segue 创建视图控制器实例时存储它们:

@property (nonatomic, strong) NSMutableDictionary *viewControllerCache;

我们稍后会在需要时对其进行初始化。

每当您响应选择菜单项时,而不是直接调用 segue,而是调用一个方法来检查缓存:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    // your logic will vary here, this is just an example

    switch(indexPath.row)
    {
        case 0:
            [self showViewControllerForSegueWithIdentifier:@"showSomething" sender:nil];
            break;
        default:
            break;
    }

}

这种缓存检查方法可能如下所示:

- (void)showViewControllerForSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{

    NSString *cacheKey = [identifier stringByAppendingFormat:@":%@", sender];
    UIViewController *dvc = [self.viewControllerCache objectForKey:cacheKey];
    if(dvc)
    {
        NSLog(@"reusing view controller from cache");
        UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
        [navController setViewControllers: @[dvc] animated: NO ];
        [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
    }
    else
    {
        NSLog(@"creating view controller from segue");
        [self performSegueWithIdentifier:identifier sender:sender];
    }

}

在这种情况下,我在缓存中创建了一个键作为 segue 名称和 sender 参数的组合。为了举例,我假设发件人是一个字符串。 sender 参数很可能不是字符串,因此您可能应该进行一些检查以确保它不会崩溃。

然后我检查视图控制器缓存是否存在任何视图控制器。如果是这样,请执行您通常在prepareForSegue:sender: 中执行的视图控制器交换(当您第一次设置 SWRevealViewController 时,您会在其中粘贴此 sn-p)。如果它不存在,则照常执行 segue(这将创建一个新实例)。

现在剩下的就是修改您的prepareForSegue:sender: 方法以在缓存中存储对实例化视图控制器的引用:

- (void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id) sender
{

    if([segue.identifier isEqualToString:@"showSomething"])
    {
        // do whatever you wish to the destination view controller here
        // ...

    }

    // this part should be very familiar
    if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] )
    {

        SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;

        swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {

            // cache the view controller
            if(self.viewControllerCache == nil) self.viewControllerCache = [NSMutableDictionary dictionary];
            NSString *cacheKey = [segue.identifier stringByAppendingFormat:@":%@", sender];
            [self.viewControllerCache setObject:dvc forKey:cacheKey];

            // the rest remains as before
            UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
            [navController setViewControllers: @[dvc] animated: NO ];
            [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
        };

    }
}

请注意,我只是在prepareForSegue:sender: 中添加了 2-3 行,这不会干扰您现有的设置。可能没有设置 segue 标识符,这将导致崩溃。您应该在 segues 上使用标识符,以便识别它们以进行缓存。

这种方法的一个限制是它只缓存从菜单视图控制器中使用 segues 调用的视图控制器。您会注意到为第一个可见视图控制器选择菜单项将导致它从头开始重新加载(因为它尚未缓存)。之后的任何时候,它都应该与缓存一起使用。我想将缓存转移到位于情节提要中的菜单设置之前的 SWRevealController 会缓解这种情况。

【讨论】:

  • 感谢您的实施,我仍然可以使用 Storyboard。使用 segues 的替代方法是使用标准的 xib 文件并从代码中执行所有操作。看看 github 页面上的第一个示例:github.com/John-Lluch/SWRevealViewController
【解决方案2】:

您可以使用 UITabBarController 来存储和重用 ViewController 只需通过 sw_front segue 制作您的 UITabBarController frontViewController, 然后从后视图控制器切换视图控制器

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
 //get tabBarController
 let tabBarVC = revealViewController().frontViewController as? UITabBarController
 //show selected ViewController
 tabBarVC.selectedIndex = indexPath.item
 revealViewController().revealToggle(animated: true)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 2020-02-27
    相关资源
    最近更新 更多