如何移除之前的视图控制器?

13

我是一名学生,对编程还很陌生。我正尝试在业余时间学习Objective-C/Swift语言。我使用Swift和SpriteKit制作了一个包含多个菜单/场景的游戏。

我正在尝试从一个视图控制器切换到另一个视图控制器。为此,我使用了以下代码:

@IBAction func PlayButtonPressed(sender: AnyObject) {
    let playStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let vc : UIViewController = playStoryboard.instantiateViewControllerWithIdentifier("playGame") as UIViewController
    self.presentViewController(vc, animated: true, completion: nil)
}
这适用于切换到新的视图控制器场景,但我认为以前的视图控制器仍然在堆栈中占用内存,会减慢我的程序速度。我已经在其他帖子上读到可以使用导航控制器来删除视图控制器的方法,但我没有导航控制器;只有视图控制器。我看到一些关于removeFromParentViewController()view.removeFromSuperview()的东西,但我不知道如何实现它。除此之外,我没有找到我要寻找的答案。
所以我的问题是怎样从堆栈中移除以前的视图控制器?任何帮助都将不胜感激!(最好使用Swift编写的帮助,但Objective-C的也可以)提前致谢! 参考注释:我相信在Objective-C中,我的代码可能如下所示:
-(IBAction) PlayButtonPressed: (id) sender {
    UIStoryboard *playStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UIViewController *vc = [playStoryboard instantiateViewControllerWithIdentifier:@"playGame"];
    [self presentViewController:vc animated:YES completion:nil];
}
5个回答

18
据我推测,展示在屏幕上的视图控制器可能是从主故事板自动实例化或通过设置应用程序的window.rootViewController属性实例化的。
无论哪种情况,您都可以将rootViewController重新设置为您的vc。要更改应用程序的rootViewController,您需要替换此行代码:
self.presentViewController(vc, animated: true, completion: nil)

使用以下选项之一来 "导航",无需转换动画。

没有转换动画的 "导航":

Objective-C

UIWindow *window = (UIWindow *)[[UIApplication sharedApplication].windows firstObject];
window.rootViewController = vc;

Swift

let window = UIApplication.sharedApplication().windows[0] as UIWindow;
window.rootViewController = vc;

带有转场动画的"导航":

Objective-C

UIWindow *window = (UIWindow *)[[UIApplication sharedApplication].windows firstObject];
[UIView transitionFromView:window.rootViewController.view
                    toView:vc.view
                  duration:0.65f
                   options:UIViewAnimationOptionTransitionCrossDissolve // transition animation
                completion:^(BOOL finished){
                    window.rootViewController = vc;
                }];

Swift

let window = UIApplication.sharedApplication().windows[0] as UIWindow;
UIView.transitionFromView(
    window.rootViewController.view,
    toView: vc.view,
    duration: 0.65,
    options: .TransitionCrossDissolve,
    completion: {
        finished in window.rootViewController = vc
    })

备注: 一旦rootViewController的值被更改,您原始的视图控制器引用计数应该变为0,因此它将从内存中删除!


当我使用这段代码时,我看到我的视图在转换结束后重新调整为正确的大小。 - João Serra

3

Swift 3

这将从内存中移除当前的视图控制器。

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    guard let viewControllers = navigationController?.viewControllers,
    let index = viewControllers.index(of: self) else { return }
    navigationController?.viewControllers.remove(at: index)
}

3
我想最好的实现方法是在前一个视图控制器中放置以下内容-Swift
    // Override to remove this view from the navigation stack
    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        // Remove self from navigation hierarchy
        guard let viewControllers = navigationController?.viewControllers,
            let index = viewControllers.indexOf(self) else { return }
        navigationController?.viewControllers.removeAtIndex(index)
    }

1
首先,您使用的是模态呈现模式,而不是导航堆栈模式(UINavigationController)。您不能摆脱呈现视图控制器,也不应该这样做,因为这会破坏导航。
简短的答案是,您不需要担心这个问题。视图控制器本身占用的内存量微不足道,并且一旦没有对它的引用(一旦您解除显示或从导航堆栈中弹出),它将自动释放。
更长的答案取决于您的具体实现。如果您在无限增加堆栈大小的情况下,那么这是一个问题。例如,如果您有一个导航流,在该流中,您可以自由地在两个“屏幕”之间移动,但每个屏幕在内部都继续呈现新屏幕,而不仅仅是切换到现有屏幕。如果您遇到类似这样的情况,则最好使用UITabBarController或类似的东西,在其中能够在视图控制器之间水平导航而不创建新的视图控制器。

-1

针对Swift 3,您可以替换

self.present(ViewController(), animated: false, completion: nil);

if let window = UIApplication.shared.keyWindow{
            window.rootViewController = UINavigationController(rootViewController: ViewController());
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接