Swift - 导航控制器没有杀死视图控制器实例

Posted

技术标签:

【中文标题】Swift - 导航控制器没有杀死视图控制器实例【英文标题】:Swift - Navigation Controller no Killing View Controller Instance 【发布时间】:2016-02-25 11:13:57 【问题描述】:

我正在使用自定义导航控制器来显示和隐藏两个 ViewController。调用 ViewController 来显示电影细节​​的代码是:

func tapGestureRecognizer(gestureRecognizer: UITapGestureRecognizer)
        self.searchBarTop.endEditing(true)
        let p = gestureRecognizer.locationInView(self.collectionViewMovies)
        let tag = gestureRecognizer.view?.tag
        if tag == 1
            if let indexPath : NSIndexPath = (self.collectionViewMovies?.indexPathForItemAtPoint(p))
                if let cell = self.collectionViewMovies.cellForItemAtIndexPath(indexPath)
                    cellAnimation.imageBlurCell(cell, style: .Light, alpha: 1.0, completion:  (complete) -> Void in
                        if let record = self.fetchedResultsController.objectAtIndexPath(indexPath) as? Movies
                            let movieId = record.movieid as! Int
                            NSNotificationCenter.defaultCenter().postNotificationName("moviesShouldGetDetails", object: nil, userInfo: ["movieId":movieId])
                            let destination = self.myStoryboard.instantiateViewControllerWithIdentifier("MovieDetails") as! MovieDetailsViewController
                            destination.movieId = movieId
                            self.navigationController?.pushViewController(destination, animated: true)
                        
                    )
                
            
        
    

我每次都在创建一个新的 MovieDetailsViewController 实例。 问题是我认为在 NavigationController Pop ViewController 之后实例会被杀死,但这并没有发生。我在 MovieDetailsViewController 中有一些观察者,我可以看到该实例仍在运行。 NavigationController 委托是:

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? 
        if operation == .Push 
            customInteractionController.attachToViewController(toVC)
        
        customNavigationAnimationController.reverse = operation == .Pop
        return customNavigationAnimationController
    

    func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? 
        return customInteractionController.transitionInProgress ? customInteractionController : nil
    

控制动画的代码如下,我尝试再次强制导航弹出,当动画完成时,但到目前为止没有运气。

import UIKit

class CustomNavigationAnimationController: NSObject, UIViewControllerAnimatedTransitioning 

    var reverse = false

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval 
        return 0.5
    

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) 
        let containerView = transitionContext.containerView()
        let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
        let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
        let toView = toViewController.view
        let fromView = fromViewController.view
        let direction: CGFloat = reverse ? -1 : 1
        let const: CGFloat = -0.005

        toView.layer.anchorPoint = CGPointMake(direction == 1 ? 0 : 1, 0.5)
        fromView.layer.anchorPoint = CGPointMake(direction == 1 ? 1 : 0, 0.5)

        var viewFromTransform: CATransform3D = CATransform3DMakeRotation(direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)
        var viewToTransform: CATransform3D = CATransform3DMakeRotation(-direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)
        viewFromTransform.m34 = const
        viewToTransform.m34 = const

        containerView!.transform = CGAffineTransformMakeTranslation(direction * containerView!.frame.size.width / 2.0, 0)
        toView.layer.transform = viewToTransform
        containerView!.addSubview(toView)

        UIView.animateWithDuration(transitionDuration(transitionContext), animations: 
            containerView!.transform = CGAffineTransformMakeTranslation(-direction * containerView!.frame.size.width / 2.0, 0)
            fromView.layer.transform = viewFromTransform
            toView.layer.transform = CATransform3DIdentity
            , completion: 
                finished in
                containerView!.transform = CGAffineTransformIdentity
                fromView.layer.transform = CATransform3DIdentity
                toView.layer.transform = CATransform3DIdentity
                fromView.layer.anchorPoint = CGPointMake(0.5, 0.5)
                toView.layer.anchorPoint = CGPointMake(0.5, 0.5)

                if (transitionContext.transitionWasCancelled()) 
                    toView.removeFromSuperview()
                 else 
                    fromView.removeFromSuperview()
                    if self.reverse
                        print("removing from superview")
                        fromViewController.navigationController?.popViewControllerAnimated(false)
                    
                
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        )
    

我在这里缺少什么?我怎样才能杀死我的 MovieDetailsViewController 实例? NavigationController .Pop 不应该杀死我的实例吗?提前致谢。

【问题讨论】:

【参考方案1】:

你说

我在 MovieDetailsViewController 中有一些观察者,我可以看到实例仍在运行。

这可能意味着您在弹出后保留了对 MovieDetailsViewController 的引用吗? Swift 的垃圾收集器不会释放视图控制器,直到它不再有任何引用。如果您保持对视图控制器的引用,即使在屏幕外,它也会保持活动状态。

【讨论】:

MovieDetailsViewController 的唯一引用是在 NSNotification NSNotificationCenter.defaultCenter().addObserver(self, selector: "movieDetailDidUpdate:", name: "movieDetailDidUpdate", object: nil) 中,我运行它时视图确实加载了。观察者可以阻止 ViewController 被释放吗?我必须删除观察者? @ClaytonAV 来自NSNotificationCenter docs "确保在notificationObserver 或addObserver:selector:name:object: 中指定的任何对象被释放之前调用removeObserver:name:object:。" 当我们学的东西不正确时,我们总是要付出代价,我现在就去读文档。非常感谢您为我指明正确的方向。稍后我将删除观察者并使用代表来查看是否可以解决我的问题。 玫瑰花。它现在可以工作了,问题出在观察者和我忘记声明为弱的 1 个代表中。 看来我错了。 MovieDetailsViewController 已解除分配,但我调用 MovieDetailsViewController 的 ViewController 仍然存在。只有当我使用自定义 NavigationController 时才会出现问题。【参考方案2】:

花了一些时间了解 ARC 的工作原理后,我能够解决问题。由于一些未声明为“弱”的代表,我有一些强参考周期。另一个问题在这一行

customInteractionController.attachToViewController(toVC)

这段代码将在另一个类中创建一个带有 NavigationViewController 的强引用,我只是将此引用更改为弱引用。现在一切正常。

【讨论】:

以上是关于Swift - 导航控制器没有杀死视图控制器实例的主要内容,如果未能解决你的问题,请参考以下文章

使用标签栏和导航实例化深度视图控制器

Swift 3 - 实例化视图控制器后没有成员错误

实例化一个保持导航栏Swift的vc

Swift:强制在模态中显示导航栏

JSQ 消息视图控制器:在导航栏上添加“返回”按钮和图像,Swift

Swift 中的多视图控制器导航