Swift iOS - Должен ли Deinit вызываться внутри дочернего View Controller при добавлении в качестве дочернего элемента к другому View Controller?
У меня есть childVC(vc3) внутри parentVC(vc2) внутри другого parentVC(vc1). Я делаю это так для анимации.
Что происходит, я добавляю vc3 как ребенка к vc2. У меня есть collectionView, который выдвигает на vc1. Как только vc1 находится на сцене, к нему добавляется vc2. Когда я вытаскиваю vc1 из стека и возвращаюсь к collectionView, вызывается deinit в vc1, однако никогда не вызывается deinit в vc2.
Должен ли deinit в vc2 вызываться, даже если он является потомком vc1? Или это возможно потому, что третий ВК создает сильную ссылку на себя внутри второго ВК?
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")
}
}
CollectionView:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let firstVC = FirstController()
navigationController?.pushViewController(firstVC, animated: true)
}
FirstVC:
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")
}
}
1 ответ
Ответ на мой вопрос: " Да, ребенок". deinit
также должен бежать. Если вы вызываете deinit внутри дочернего контроллера представления и когда родитель выталкивается из сцены (или увольняется), а дочерний deinit не запускается, тогда у вас есть проблема.
Как отметил @BadhanGanesh в комментариях, он спросил:
" Используете ли вы какие-либо уведомления наблюдателей, что вы не можете удалить их, когда они не нужны "
И @Bruno Pinheiro предложил в комментариях:
" Кажется, это серьезный вопрос "
Они оба были правы. Я просмотрел весь код и подумал, что удалил наблюдателя из КВО, но не сделал этого.
Короче говоря, если у вас есть View Controller, который является дочерним по отношению к другому View Controller (родительскому), то после того, как родительский объект освобождается, должен поступить и дочерний.
Если вы используете каких-либо наблюдателей 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)
}
}
}
}