[英]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.