Почему deinit не вызывается до тех пор, пока UIView снова не будет добавлен к родителю?

У меня есть UIView, который я добавляю к UIViewController, и обычно я тестирую деинициализацию, чтобы убедиться, что я все делаю правильно. Но когда я не устанавливаю переменную в моем viewController на nil и использую только .removeFromSuperView() , метод deinit() в UIView не будет вызываться, пока я не добавлю UIView в другой раз, а затем его вызов. Но если я использую removeFromSuperView() и устанавливаю переменную в nil, то сразу же вызывается deinit(). Почему это?

Вот класс UIView():

class TestView: UIView {

    override init(frame: CGRect) {
        super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        print("init is happneing")
    }

    deinit {
        print("de init is happneing")
    }


    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Вот родительский ViewController:

class MyViewController: UIViewController { 
 var tstview  : TestView?


  //adding the UIView by tapping on a button 
 @IBAction func addView(_ sender: UIButton) {

        let test = TestView()
        tstview = test
        tstview?.frame = CGRect(x: 50, y: 60, width: self.view.frame.width-100, height: self.view.frame.height-200)
        tstview?.backgroundColor = UIColor.white
        self.view.addSubview(tstview!)  
}

    override func viewDidLoad() {
       super.viewDidLoad()  
    }

    //removing UIView by touching elsewhere 
   override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
         tstview?.removeFromSuperview()
      //  tstview = nil

    }


}

person TheeBen    schedule 04.03.2017    source источник
comment
Привет. Вы когда-нибудь получали ответ на это?   -  person Anthony    schedule 07.02.2021


Ответы (1)


deinit вызывается, когда никто не ссылается на объект. Если вы не установите tstview в nil, ваш MyViewController все еще ссылается на него, поэтому deinit не будет вызываться. Когда вы вызываете addView, оператор tstview = test окончательно удаляет последнюю ссылку на старое представление, тем самым запуская деинициализатор.

Подробнее о концепции деинициализации можно прочитать в документации по Swift. .


Если вы хотите получать уведомления, как только представление будет отключено, переопределите willMove(toSuperview:) вместо этого.

class TestView: UIView {
    ...
    override func willMove(toSuperview newSuperview: UIView?) {
        if newSuperview == nil {
            print("removed from parent")
        }
    }
}
person kennytm    schedule 04.03.2017
comment
Спасибо за ответ, я хочу убедиться, что не оставлю никаких утечек, что в этом случае, как я понимаю, willMove toSuperview не поможет. Я пытаюсь понять, почему removeFromSuperview() не выполняет деинициализацию, пока я не добавлю еще один экземпляр UIView() в свой родительский контроллер, потому что тогда и только тогда я вижу, что деинит вызывается. Я просмотрел документы, но не могу найти причину. - person TheeBen; 04.03.2017