Deinit не вызвал UIViewController, но Dealloc
Он кажется, что эквивалент Swift dealloc
- deinit
. Однако, когда вы пытаетесь определить метод на UIViewController, он не ведет себя так, как вы ожидали бы...
Настройка
- Создайте новый проект Single View с помощью Xcode 7.0 в Swift или Objective-C.
- Добавьте кнопку "увольнение" на контроллере представления, который был создан с помощью раскадровки (я буду ссылаться на этот контроллер представления как VC2, его класс - ViewController).
- Добавить новый контроллер представления и установить его как начальный контроллер представления (VC1, класс - nil).
- Добавьте кнопку "настоящее" в VC1 с "текущим моментом" до VC2.
- В коде VC2 поместите точку останова в
deinit
(Swift) или dealloc
(Objective-C).
-
В VC2 сделайте действие кнопки "увольнение" следующим образом:
// Swift:
presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
// Objective-C:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
- Запустите приложение и нажмите обе кнопки, чтобы сначала представить VC2, а затем отпустите его.
Обратите внимание, что в Objective-C, точка останова dealloc
нажата.
В Swift, с другой стороны, точка останова deinit
никогда не попадает.
Почему deinit
никогда не вызывается? Является ли это ошибкой или по дизайну?
Если это по дизайну, где я должен поместить очищающий код, чтобы освободить ресурсы, когда контроллер просмотра больше не понадобится? (Он не может быть в viewDidUnload
, поскольку этот метод устарел. Он не может быть в viewDidDisappear
, потому что что-то еще может содержать ссылку на него и в конечном итоге отобразит его снова.)
Примечание. Если вы попытаетесь определить метод dealloc
в Swift, вы получите следующую ошибку:
Метод 'dealloc()' с Objective-C selector 'dealloc' конфликтует с деинициализатором с тем же селектором Objective-C.
Если у вас есть контроллер представления Swift наследуется от контроллера Objective-C, и вы помещаете точку останова в метод dealloc Objective-C, вы получите такое же неправильное поведение, как указано выше: deinit
не будет вызываться, но будет вызван dealloc
.
Если вы пытаетесь использовать Allocations для просмотра количества экземпляров класса в памяти, обе версии показывают одно и то же: # Persistent
всегда 1, а # Transient
увеличивается каждый раз, когда вы показываете второй контроллер представления.
Учитывая выше настройки, не должно быть никаких сильный опорный цикл держась контроллера представления.
Ответы
Ответ 1
TL;DR:
Точки останова будут работать только в deinit
, если перед ними есть исполняемая строка кода.
- Если вы поместите точку останова на строку исполняемого кода, она будет работать.
- Исполняемая строка кода должна принадлежать методу
deinit
.
Благодаря Адам за то, что указал мне в правильном направлении. Я не проводил обширных тестов, но похоже, что точки останова ведут себя по-другому в deinit
, чем везде в вашем коде.
Я покажу вам несколько примеров, когда я добавил точку останова на номер строки каждый. Те, которые будут работать (например, приостановить выполнение или выполнить их действие, например, протоколирование сообщения), будут отображаться с помощью символа..
Обычно точки останова ударяются либерально, даже если метод ничего не делает:
➤ 1
➤ 2 func doNothing() {
➤ 3
➤ 4 }
5
Однако в пустом методе deinit
будут удалены точки останова NO:
1
2 deinit {
3
4 }
5
Добавляя больше строк кода, мы можем видеть, что это зависит от того, существует ли исполняемая строка кода, следующая за точкой останова:
➤ 1
➤ 2 deinit {
➤ 3 //
➤ 4 doNothing()
➤ 5 //
➤ 6 foo = "abc"
7 //
8 }
9
В частности, обратите особое внимание на строки 7 и 8, так как это значительно отличается от того, как вел себя doNothing()
!
Если вы привыкли к такому поведению, как точка останова в строке 4 работала в doNothing()
, вы можете ошибочно вывести, что ваш код не выполняется, если вы только имели точку останова в строке 5 (или даже 4) в этом примере
➤ 1
➤ 2 deinit {
➤ 3 number++
4 // incrementNumber()
5 }
6
Примечание: для точек останова, которые приостанавливают выполнение в одной строке, они попадают в том порядке, в котором они были созданы. Чтобы проверить их порядок, я установил точку останова для сообщения журнала и автоматически продолжу после оценки действий.
Примечание. В моем тестировании также возникла еще одна потенциальная ошибка, которая может привести к вам: если вы используете print("test")
, она отобразит область отладки, чтобы отобразить сообщение (сообщение выделено жирным шрифтом). Однако, если вы добавите точку останова и сообщите ей Сообщение журнала, она будет записывать ее в обычный текст, а не всплывает область отладки. Вы должны вручную открыть область отладки, чтобы увидеть результат.
Примечание. Все это было протестировано в Xcode 7.1.1
Ответ 2
Я еще не пробовал, но я нашел этот для вас:
Кажется, что функция не будет вызываться, если какой-либо код не вставлен в deinit (странный), должен быть частью быстрой стадии оптимизации.
Попробуйте поместить выражение печати внутри своего deinit, как было предложено, и сообщить о своих результатах