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

Деинит никогда не называл

Я создаю объект ViewController и нажимаю его на контроллер навигации. Когда объект выталкивается из стека - он не выпускается, и Deinit не вызывается. Что может быть причиной этого?

Вот код, который толкает:

self.navigationController?.pushViewController(CustomViewController(), animated: true)

И вот код, который появляется:

 self.navigationController?.popViewControllerAnimated(true)
4b9b3361

Ответ 1

У меня была аналогичная проблема. Я добавил пустой метод deinit к моему классу и добавил точку останова:

deinit {

}

В результате он никогда не назывался.
Как только я добавлю код в тело, он начал работать как ожидалось:

deinit {
    print("deinit called")
}

Поэтому убедитесь, что ваш метод deinit не пуст.
PS. Я использую Swift 2, Xcode 7.1

Ответ 2

У вас есть какие-либо из ваших классов или свойства, которые они содержат, ссылаются на контроллер вида, который вы выскочили?

Если ваш UIViewController создал экземпляр объекта, который, в свою очередь, делает "сильную" ссылку на этот контроллер представления (например, ссылку, которая явно не объявлена ​​ "слабой" или "незаслуженной" ), и ваш контроллер просмотра сохраняет сильная ссылка на этот объект также не будет освобождена. Это называется сильным эталонным циклом, зарегистрированным здесь (обязательно для серьезных разработчиков Swift):

Язык Swift для программирования (Swift 3.0.1): автоматический подсчет ссылок

Закрытие - более коварный случай, когда вы можете попасть в неприятности.

Одна вещь, которую вы можете попробовать в качестве эксперимента, - это нажать контроллер и выскочить, прежде чем делать что-либо в viewDidLoad или в инициализации, и посмотреть, вызывается ли метод deinit. Если это так, то вы должны иметь возможность постепенно обнаруживать, что вы делаете, что приводит к симптому, который вы видите.

Еще одна вещь, которая может помешать диагнозу (как указывали другие ответы), который я усвоил, заключается в том, что точка останова отладчика не будет использоваться для deinit(), если метод deinit не содержит исполняемых инструкций, поскольку OS или компилятор оптимизирует вызов deinit, если он пуст, поэтому по крайней мере ставьте там инструкцию печати, если вы хотите проверить, что вызов deinit() вызывает.

Ответ 3

Я использовал этот учебник Custom TabBar с пользовательской настройкой на данной странице. Проблема с памятью была вызвана подзадачей, которая имела сильную ссылку на родительский контроллер представления.

class WBMNewsFeedV: UIView
{
   var parentVC:WBMHomeTabVC!
}

WBMNewsFeedV - подкласс

parentVC: WBMHomeTabVC - родительский класс ViewController

Я изменил его на:

class WBMNewsFeedV: UIView
{
    weak var parentVC:WBMHomeTabVC!
}

Итак, сильная ссылка была вложена внутри subviews и не видна вначале. Надеюсь, это поможет кому угодно. После изменения deinit всегда вызывался в

WBMHomeTabVC

Ответ 4

У меня была такая же проблема, когда в NotificationCenter была сильная ссылка на представленный контроль, и поэтому он так и не был выпущен. Поэтому мне пришлось добавить [слабый я] в блок следующим образом:

(в viewDidLoad)

NotificationCenter.default.addObserver(forName: .showFoo, object: nil, 
  queue: OperationQueue.main) { [weak self] (notification) in
    if let foo = notification.userInfo?["foo"] as? Foo {
            self?.afooButton!.setImage(UIImage(named: "foo"), for: .normal)
    }
}

Ответ 5

У меня был таймер в моем контроллере просмотра, который запускался каждую минуту, чтобы обновить ярлык. Я поставил вызов в deinit, чтобы аннулировать таймер, и я уверен, что это всегда было сделано в Objective-C (в dealloc), и это сработало. Но в Swift это немного отличается, поэтому я переместил код создания времени/недействительности в viewWillAppear/viewWillDisappear (что на самом деле имеет больше смысла), и теперь все кажется прекрасным!

Ответ 6

Я столкнулся с подобной проблемой. Моя проблема, по-видимому, вызвана сильной ссылкой на элемент управления, у которого присваивание делегата не указано как "слабый" с протоколом типа класса.

Ответ 7

добавить код строки в deinit. Если вы поставили точку останова в Empty deinit, компилятор не остановит вас там поместите это:

deinit {
print("any thing")
}

Он будет работать;)

Ответ 8

Я столкнулся с той же проблемой. В моем случае бесконечный цикл UIView.animateWithDuration... содержит ViewController в памяти и блокирует вызов deinit. Если вы используете что-то вроде этого, вам нужно сначала остановить его, чтобы удалить ViewController. Надеюсь, что это поможет.

Ответ 9

Просто чтобы добавить крайний случай, который мне было очень трудно обнаружить:

Если вы выделяете какие-либо UnsafeMutablePointers и предоставляете self (UIViewController) в качестве pointee внутри вашего контроллера представления, обязательно вызовите pointer.deinitialize(count:), а не просто pointer.deallocate().

В противном случае ссылка на self останется, а UIViewController не будет деинициализирован.

Ответ 10

Прежде всего, убедитесь, что определение deinit

deinit {
    print("OverlayView deinit")
}

Используйте граф объектов Xcode для проверки количества создаваемых экземпляров, и если они не будут освобождены, они будут расти. Я создавал свойство другого ViewController поверх файла, поэтому я переместил его и поместил в область, в которой он использовался, что решило мою проблему. И его деинит зазвонил.

Более того, я использовал свойство uiview, чтобы показать наложение, к которому нужно обращаться из моего viewcontroller, в некоторых местах, я делаю его необязательным и устанавливаю его равным nil, когда после вызова removefromsuperview для него.

var overlay: OverlayView?
overlay = nil

Если все еще dealloc не вызывает, то может возникнуть проблема сохранения цикла, как описано выше, в этом случае вам придется также проверить другой viewcontroller (B), если он вызывает этот контроллер (A), а затем установить один из них как слабую переменную.

Ответ 11

У меня была похожая проблема: у меня были некоторые UIViews как упорядоченные подпредставления * stackview ", содержащиеся в scrollview в контроллере подробного представления. Это работало, когда я удалял UIViews из stackView при нажатии кнопки назад (willMove(toParent parent: UIViewController?)). Еще одна вещь, которую нужно проверить, - это когда в вашем контроллере представления есть что-то вроде: let session = URLSession(configuration:.default, delegate: self, delegateQueue: OperationQueue()) (что self может в некоторых случаях предотвратить контроллер подробного представления быть освобожденным при нажатии Back и переходе к мастеру)

Ответ 12

У меня была та же проблема, что я обнаружил, я не делал слабую ссылку для моего другого представителя класса

protocol SomeClassDelegate : AnyObject {
    func someClassDelegateMethod(<param>)
}

class SomeClass: NSObject {

    // Make delegate weak reference 
    weak var delegate:InfractionDataManagerDelegate? = nil
    < some code >
}

теперь deinit вызывается в моем классе реализации.