Swift - 导航控制器没有杀死视图控制器实例
Swift - Navigation Controller no Killing View Controller Instance
我正在使用自定义导航控制器来显示和隐藏两个 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 不应该杀死我的实例吗?提前致谢。
你说
I have some Observers inside the MovieDetailsViewController and i can see that the instance still running.
这是否可能意味着您在弹出后保留对 MovieDetailsViewController 的引用? Swift 的垃圾收集器不会释放视图控制器,直到它不再有任何引用。如果您维护对视图控制器的引用,即使在屏幕外它也会保持活动状态。
在花了一些时间了解 ARC 的工作原理后,我解决了这个问题。我有一些强引用循环,因为一些委托没有像 "weak" 这样声明。另一个问题是在这一行
customInteractionController.attachToViewController(toVC)
此代码将在另一个 class 中使用 NavigationViewController 创建强引用,我只是将此引用更改为弱引用。现在一切正常。
我正在使用自定义导航控制器来显示和隐藏两个 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 不应该杀死我的实例吗?提前致谢。
你说
I have some Observers inside the MovieDetailsViewController and i can see that the instance still running.
这是否可能意味着您在弹出后保留对 MovieDetailsViewController 的引用? Swift 的垃圾收集器不会释放视图控制器,直到它不再有任何引用。如果您维护对视图控制器的引用,即使在屏幕外它也会保持活动状态。
在花了一些时间了解 ARC 的工作原理后,我解决了这个问题。我有一些强引用循环,因为一些委托没有像 "weak" 这样声明。另一个问题是在这一行
customInteractionController.attachToViewController(toVC)
此代码将在另一个 class 中使用 NavigationViewController 创建强引用,我只是将此引用更改为弱引用。现在一切正常。