简体   繁体   English

Swift iOS - 当作为子视图控制器添加到另一个视图控制器时,是否应该在子视图控制器中调用 Deinit?

[英]Swift iOS -Should Deinit get called inside child View Controller when added as a child to another View Controller?

I have a childVC(vc3) inside a parentVC(vc2) inside another parentVC(vc1).我在另一个 parentVC(vc1) 中的 parentVC(vc2) 中有一个 childVC(vc3)。 I'm doing it this way for animation purposes.我这样做是为了动画目的。

What happens is I add vc3 as a child to vc2.发生的事情是我将 vc3 作为子项添加到 vc2。 I have a collectionView that pushes on vc1.我有一个推送 vc1 的 collectionView。 Once vc1 is on scene vc2 is added to it.一旦 vc1 出现在场景中,vc2 就会被添加到其中。 When I pop vc1 off the stack and go back to the collectionView the deinit in vc1 gets called however the deinit in vc2 never gets called.当我从堆栈中弹出 vc1 并返回到 collectionView 时,vc1 中的 deinit 被调用,但是 vc2 中的 deinit 永远不会被调用。

Is the deinit in vc2 supposed to get a called even though it's a child of vc1? vc2 中的 deinit 是否应该被调用,即使它是 vc1 的子级? Or is it possibly because the thirdVC is creating a strong reference to itself inside of the secondVC?或者可能是因为 thirdVC 在 secondVC 内部创建了对自身的强引用?

SecondVC with the ThirdVC added inside of it:在其中添加了 ThirdVC 的 SecondVC:

class SecondController: UIViewController {

override func viewDidLoad() {
        super.viewDidLoad()

        let thirdVC = ThirdController()
        addChildViewController(thirdVC)
        view.addSubview(thirdVC.view)
        thirdVC.didMove(toParentViewController: self)
}

 // this never runs when the firstVC is popped off the stack
deinit{
     print("the secondVC has be deallocated")
}
}

CollectionView:集合视图:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let firstVC = FirstController()
        navigationController?.pushViewController(firstVC, animated: true)
    }

FirstVC:第一VC:

class FirstController: UIViewController {

override func viewDidLoad() {
        super.viewDidLoad()

        let secondVC = SecondController()
        addChildViewController(secondVC)
        view.addSubview(secondVC.view)
        secondVC.didMove(toParentViewController: self)
}

// this runs when popped off the stack
deinit{
     print("the firstVC has be deallocated")
}
}

The answer to my question is Yes the child View Controller's deinit should also run.我的问题的答案是是的,子视图控制器的deinit也应该运行。 If you call deinit inside the child view controller and when the parent is popped of the scene (or dismissed) and the child's deinit doesn't run then you have a problem.如果您在子视图控制器中调用 deinit,并且当父级从场景中弹出(或被解雇)并且子级的 deinit 没有运行时,那么您就有问题了。

As @BadhanGanesh pointed out in the comments he asked:正如@BadhanGanesh 在评论中指出的那样,他问:

" are you using any notification observers that you fail to remove them when not needed " 你是否在使用任何通知观察者,你在不需要时没有将它们移除

And @Bruno Pinheiro suggested in the comments: @Bruno Pinheiro 在评论中建议:

" It seems to be a strong reference issue " 好像是很强的参考题

They were both right.他们都是对的。 I looked through all the code and I thought I had removed a KVO observer but I didn't.我查看了所有代码,我以为我已经删除了 KVO 观察器,但我没有。

Long story short if you have a View Controller that is a child of another View Controller (parent) then once the parent is deallocated then so should the child.长话短说,如果您有一个 View Controller 是另一个 View Controller(父级)的子级,那么一旦父级被释放,子级也应该被释放。

If your using any KVO observers inside either the parent or child then make sure you remove them or you will create a strong retain cycle.如果您在父对象或子对象中使用任何 KVO 观察者,请确保删除它们,否则您将创建一个强大的保留循环。

I needed to pass "weak self" to firebase observer in parent view controller to remove the retain cycle, then deinit was called on both parent and child controllers:我需要将“弱自我”传递给父视图控制器中的 firebase 观察者以删除保留周期,然后在父控制器和子控制器上调用 deinit:

    func observeFeatureChanged(){
    microbeRef.queryOrdered(byChild: Nodes.TIMESTAMP)
        .observe(.childChanged) { [weak self] (dataSnapshot) in
            if let featureDic = dataSnapshot.value as? [String: Any]{
                let featureName = dataSnapshot.key
                if let index = self?.featureNames.firstIndex(of: featureName){
                    self?.featureNames[index] = featureName
                    self?.featureDictionaries[index] = featureDic
                    let indexpath = IndexPath(item: index, section: 0)
                    self?.tableView.reloadRows(at: [indexpath], with: .automatic)
                }
            }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将其添加到新的keyWindow时,将运行Swift iOS -View Controller deinit - Swift iOS -View Controller deinit runs when adding it to a new keyWindow 为什么即使没有将视图控制器显式添加为子视图,也要调用外观方法? - Why do appearance methods get called even when the view controller is not explicitly added as a child? 添加子视图控制器swift - Add child view controller swift deinit 仅在视图控制器打开时被调用 - deinit only gets called when view controller opens 当视图控制器消失时,将调用deinit吗? - Will deinit gets called when a view controller gets disappeared? 关闭视图控制器时,在应用程序中调用了deinit,但未在单元测试中调用过deinit - deinit called in app but not in unit test when dismissing view controller iOS:子视图 Controller 解雇导致再次调用 viewDidLoad - iOS: Child View Controller dismissal causes viewDidLoad to be called again iOS 13 在标签栏子视图中 controller viewWillAppear 未被调用 - iOS 13 In Tab Bar child view controller viewWillAppear is not called 如何使用Swift在iOS 8中正确添加子视图控制器 - How To Properly Add Child View Controller in iOS 8 With Swift iOS-将子视图添加到子视图控制器视图 - iOS - Adding Subviews to Child View Controller view
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM