Swift iOS - 当作为子视图控制器添加到另一个视图控制器时,是否应该在子视图控制器中调用 Deinit?
Swift iOS -Should Deinit get called inside child View Controller when added as a child to another View Controller?
我在另一个 parentVC(vc1) 中的 parentVC(vc2) 中有一个 childVC(vc3)。我这样做是为了动画目的。
我将 vc3 作为子项添加到 vc2。我有一个推送 vc1 的 collectionView。一旦 vc1 出现在场景中,vc2 就会被添加到其中。当我从堆栈中弹出 vc1 并返回到 collectionView 时,vc1 中的 deinit 被调用但是 vc2 中的 deinit 永远不会被调用。
vc2 中的 deinit 是否应该被调用,即使它是 vc1 的子级?或者可能是因为 thirdVC 在 secondVC 内部创建了对自身的强引用?
SecondVC 添加了 ThirdVC:
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")
}
}
集合视图:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let firstVC = FirstController()
navigationController?.pushViewController(firstVC, animated: true)
}
第一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")
}
}
我的问题的答案是 是的 child View Controller 的 deinit
也应该 运行。 如果你在 child 视图控制器,当 parent 从场景中弹出(或关闭)并且 child 的 deinit 没有 运行 那么你就有问题了。
正如@BadhanGanesh 在评论中指出的那样,他问:
"您是否使用任何通知观察器,但在不需要时未能将其移除"
@B运行o Pinheiro 在评论中建议:
"好像是个参考性很强的问题"
他们都是对的。我查看了所有代码,我以为我已经删除了 KVO 观察器,但我没有。
长话短说,如果您的视图控制器是另一个视图控制器 (parent) 的 child,那么一旦 parent 被释放,那么 [=33] 也应该被释放=].
如果您在 parent 或 child 中使用任何 KVO 观察器,请确保删除它们,否则您将创建一个强大的保留循环。
我需要将 "weak self" 传递给父视图控制器中的 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)
}
}
}
}
我在另一个 parentVC(vc1) 中的 parentVC(vc2) 中有一个 childVC(vc3)。我这样做是为了动画目的。
我将 vc3 作为子项添加到 vc2。我有一个推送 vc1 的 collectionView。一旦 vc1 出现在场景中,vc2 就会被添加到其中。当我从堆栈中弹出 vc1 并返回到 collectionView 时,vc1 中的 deinit 被调用但是 vc2 中的 deinit 永远不会被调用。
vc2 中的 deinit 是否应该被调用,即使它是 vc1 的子级?或者可能是因为 thirdVC 在 secondVC 内部创建了对自身的强引用?
SecondVC 添加了 ThirdVC:
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")
}
}
集合视图:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let firstVC = FirstController()
navigationController?.pushViewController(firstVC, animated: true)
}
第一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")
}
}
我的问题的答案是 是的 child View Controller 的 deinit
也应该 运行。 如果你在 child 视图控制器,当 parent 从场景中弹出(或关闭)并且 child 的 deinit 没有 运行 那么你就有问题了。
正如@BadhanGanesh 在评论中指出的那样,他问:
"您是否使用任何通知观察器,但在不需要时未能将其移除"
@B运行o Pinheiro 在评论中建议:
"好像是个参考性很强的问题"
他们都是对的。我查看了所有代码,我以为我已经删除了 KVO 观察器,但我没有。
长话短说,如果您的视图控制器是另一个视图控制器 (parent) 的 child,那么一旦 parent 被释放,那么 [=33] 也应该被释放=].
如果您在 parent 或 child 中使用任何 KVO 观察器,请确保删除它们,否则您将创建一个强大的保留循环。
我需要将 "weak self" 传递给父视图控制器中的 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)
}
}
}
}