Swift Retain Cycle Issue при настройке с помощью метода экземпляра - PullRequest
0 голосов
/ 18 февраля 2019

Если я создам класс Agent, подобный этому.который содержит слабую ссылку на другой объект агента.

class Agent {

    weak var partner: Agent?
    var name: String

    init(name: String) {
        self.name = name
    }

    func makePartner(_ agent: Agent?) {
        partner = agent
        agent?.partner = self
    }

    deinit {
        print("Deinit for \(name)")
    }
}

var sam: Agent? = Agent(name: "Sam")

var bond: Agent? = Agent(name: "Bond")

//sam?.partner = bond //THIS WORKS
//bond?.partner = sam //THIS WORKS

bond?.makePartner(sam) //THIS DOESN'T WORK (deinit called for bond but not sam

sam = nil
bond = nil

Если я устанавливаю партнерство с помощью метода makePartner, а затем устанавливаю оба объекта равными nil, то вызывается только deinit облигации, а не sam.

Но если я использую

sam?.partner = bond //THIS WORKS
bond?.partner = sam //THIS WORKS

вместо вызова makePartner, то вызывается оба deinit.Вы можете объяснить, почему это происходит?какая ссылка остается на sam при настройке партнера с помощью метода makePartner.

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Там нет «сильного опорного цикла» (ранее известно «сохранить цикл») здесь.Ваши weak ссылки предотвращают это.

Невозможность увидеть свидетельство освобождения обоих объектов является , а не результатом кода в вашем вопросе.Это просто своеобразное поведение игровой площадки.

Если вы запускаете это в приложении, оно работает нормально.

И, что интересно, когда я тестировал это на игровой площадке Xcode 10.2 beta 2, он тоже там правильно себя вел.


Если оставить в стороне эту проблему, есть пара проблем сmakePartner.Держу пари, что вам все равно, что это просто проверка слабых отношений, но если вам все равно, я бы хотел уточнить вопросы:

  • Что если«А» был партнером с «В», но теперь мы хотим сделать его партнером с «С».Ваш код сделает партнеров «А» и «С» друг для друга, но «Б» все еще будет болтаться там, все еще думая, что его партнеры с «А», хотя это не так.

  • Или что, если «C» ранее был партнером с «D», теперь, когда он был переназначен на «A», нам действительно нужно сообщить «D», что он больше не партнер с«C».

  • Или давайте предположим, что «A» был партнером с «B», и теперь мы хотим сказать, что у него нет партнера, то есть, что его партнером является nil.Опять же, мы должны сообщить «B», что его партнер также nil, а не «A».

  • Наконец, как вы можете видеть, этот «один человек может быть толькоПартнерские отношения с кем-то другим ». Взаимосвязанная структура является хрупкой, мы действительно хотим убедиться, что никакой внешний код не может изменить чьего-либо партнера, а может сделать это только через makePartner.

0 голосов
/ 18 февраля 2019

Это проблема, связанная с игровой площадкой.В коде приложения выше работает просто отлично.Если вы все еще хотите решить эту проблему на игровой площадке, вы можете исправить это поведение, заменив:

bond?.makePartner(sam) - this line

на следующие строки:

bond?.partner = sam
sam?.partner = bond
...