Ios SWRevealviewController片段,重用ViewController
我使用的是SWRevealViewController,我使用的是自定义segue,我注意到每次执行segue时,SWRevealViewController都会创建一个全新的目标控制器实例,有没有一种方法可以让SWRevealViewController重用viewcontroller?重用视图控制器的实例实际上非常简单,而且不需要修改SWRevealViewController 在指定的MenuViewController(每当您希望显示菜单项的视图控制器时,负责调用segues的视图控制器)中,创建视图控制器缓存。无论何时通过segue创建视图控制器实例,都将使用该选项来存储它们:Ios SWRevealviewController片段,重用ViewController,ios,objective-c,uiviewcontroller,Ios,Objective C,Uiviewcontroller,我使用的是SWRevealViewController,我使用的是自定义segue,我注意到每次执行segue时,SWRevealViewController都会创建一个全新的目标控制器实例,有没有一种方法可以让SWRevealViewController重用viewcontroller?重用视图控制器的实例实际上非常简单,而且不需要修改SWRevealViewController 在指定的MenuViewController(每当您希望显示菜单项的视图控制器时,负责调用segues的视图控制器
@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) 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];
};
}
}
此缓存检查方法可能如下所示:
- (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参数的组合。为了举例说明,我假设发送者是一个字符串。发送方参数很可能不是字符串,因此您可能应该进行一些检查以确保它不会崩溃
然后检查视图控制器缓存是否存在任何视图控制器。如果是这样,请执行您通常在prepareforsgue:sender:
中执行的视图控制器交换(当您第一次设置SWRevealViewController时,您会将此代码段粘贴到其中)。如果不存在,则按正常方式执行segue(这将创建一个新实例)
现在只剩下修改prepareforsgue:sender:
方法,将对实例化视图控制器的引用存储在缓存中:
- (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) 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];
};
}
}
请注意,我只是在prepareforsgue:sender:
中添加了2-3行,这不会干扰您现有的设置。可能未设置segue标识符,这将导致崩溃。您应该在segue上使用标识符,以便识别它们进行缓存
这种方法的一个限制是,它只缓存通过菜单视图控制器的分段调用的视图控制器。您会注意到,为第一个可见视图控制器选择菜单项将导致重新加载它(因为它尚未缓存)。在此之后的任何时候,它都应该与缓存一起工作。我想象将缓存转移到位于序列图像板中菜单设置之前的SWRevealController将缓解这一问题。您可以使用UITabBarController存储和重用ViewController 只需通过sw_front segue使您的UITabBarController frontViewController, 然后从后viewController切换viewController
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)
}
分段总是实例化新的控制器,所以不能重用它们。我不熟悉SWRevealViewController,但如果你能用代码而不是使用segue来推送或呈现控制器,那就是你需要做的。嗨@rdelmar,你给出的有趣评论,我有一个后续问题:如果segues总是实例化新的控制器,不使用它们并且总是尝试推送或呈现代码,这难道不是合乎逻辑的吗?就像一般做法一样,不一定。很多时候,当你转到一个控制器时,你想实例化一个新的控制器,然后在你返回时取消分配它(通过弹出、取消或使用一个展开序列)。你是否使用它们取决于你的应用程序的工作流程。由于你的实现,我仍然可以使用故事板。使用segues的替代方法是使用标准的xib文件,并从代码开始执行所有操作。请看github页面上的第一个示例: