Подтвердить что ты не робот

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 увеличивается каждый раз, когда вы показываете второй контроллер представления.

Учитывая выше настройки, не должно быть никаких сильный опорный цикл держась контроллера представления.

4b9b3361

Ответ 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, как было предложено, и сообщить о своих результатах