GCD сохраняет четкую ссылку на "себя" даже при определении списка захвата

class MyClass {
    var someProperty = 0

    deinit {
        // never gets called
    }

    func doSomething() {
        DispatchQueue.global().async { [weak self] in
            Thread.sleep(forTimeInterval: 3600)
            self?.someProperty = 123
        }
    }
}

class MyViewController: UIViewController {
    var myClass: MyClass?

    deinit {
        // MyViewController gets properly deallocated
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        myClass = MyClass()
        myClass?.doSomething()
    }
}

При выполнении вышеуказанного кода MyClass никогда не освобождается, даже когда MyViewController извлекается из стека навигации или удаляется.

Однако, если я перенесу реализацию MyClass непосредственно на MyViewController, все будет работать как положено:

class MyViewController: UIViewController {
    var someProperty = 0

    deinit {
        // MyViewController still gets properly deallocated
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        DispatchQueue.global().async { [weak self] in
            Thread.sleep(forTimeInterval: 3600)
            self?.someProperty = 123
        }
    }
}

Я использовал график отладочной памяти, чтобы выяснить, что все еще хранит ссылку на экземпляр MyClass, и вот что я получаю:

Почему до сих пор есть ссылка? Что мне здесь не хватает?

ОБНОВИТЬ

Поэтому я пытался выяснить, почему он работает с MyViewController, но не при наличии другого экземпляра между ними. Кажется, что наследование от NSObject имеет значение. Когда я наследую MyClass от NSObject, вызывается deinit, и как только длинная операция завершается, для self тогда правильно устанавливается значение nil.

Теперь возникает вопрос, каким образом списки захвата в Swift связаны с NSObject?

0 ответов

Другие вопросы по тегам