В замыкании Swift что меняет capture list в момент захвата внешних переменных?
Capture list задаёт, какие значения замыкание сохранит при создании, вместо обычного захвата внешнего хранилища переменной. Для типов-значений это обычно означает снимок текущего значения, а для экземпляра класса — копирование ссылки, но не объекта. Capture list также позволяет явно выбрать weak или unowned захват и тем самым управлять временем жизни объекта.
Замыкания часто переживают функцию, в которой были созданы, поэтому им нужно сохранять используемые внешние данные. Без явного управления захватом это может неожиданно продлить жизнь объектов или привести к тому, что замыкание будет видеть последующие изменения переменной.
Capture list предоставляет декларативный способ зафиксировать значения и выразить отношение владения объектом. Это особенно важно для обработчиков событий, отложенных операций и замыканий, хранящихся внутри объектов.
Если замыкание захватывает изменяемую переменную без capture list, оно обращается к захваченному хранилищу. Поэтому изменения переменной до или после создания замыкания могут быть видны при его вызове, а несколько замыканий могут разделять одно состояние.
При захвате экземпляра класса по умолчанию сохраняется сильная ссылка. Если объект хранит такое замыкание, возникает цикл сильных ссылок: объект удерживает замыкание, а замыкание удерживает объект. Объект тогда не освобождается после исчезновения внешних ссылок.
Элементы capture list вычисляются при создании замыкания. Запись значения в список захвата фиксирует текущее значение; последующее переназначение исходной переменной не меняет сохранённое значение.
Для значения типа-значения сохраняется отдельная копия или логически независимое значение. Если захвачено значение ссылочного типа, копируется сама ссылка: замыкание и исходная переменная указывают на один объект, поэтому изменения его свойств видны через обе ссылки.
weak захватывает объект без владения. После освобождения объекта такая ссылка становится nil, поэтому обращение обычно требует optional binding или другой проверки. unowned также не удерживает объект, но предполагает, что объект гарантированно будет жив в момент обращения; нарушение этого условия приводит к аварийному завершению.
Capture list может содержать и вычисляемые выражения с собственными именами. Это позволяет один раз вычислить зависимость при создании замыкания, а не получать её заново при каждом вызове.
Главный компромисс таков: сильный захват проще и безопаснее с точки зрения доступности объекта, но может создать цикл; weak предотвращает цикл, но добавляет optional-семантику; unowned не требует optional-проверки, однако ошибка жизненного цикла становится фатальной.
Экран хранит обработчик завершения сетевой операции, а обработчик обращается к этому экрану. При сильном захвате экран может удерживать обработчик, а обработчик — экран, поэтому после закрытия экрана память не освобождается.
Можно явно разорвать цикл через weak захват. Это наиболее безопасный вариант для интерфейсных объектов: если экран уже уничтожен, обработчик просто ничего не выполняет. Минус — необходимость обработать отсутствие объекта.
Unowned подходит только при доказуемо более короткой жизни замыкания по сравнению с объектом, например если объект гарантированно переживает зарегистрированный callback. Его плюс — отсутствие optional-проверок, но цена ошибки выше: обращение к освобождённому объекту завершит программу.
Практический выбор для асинхронных задач обычно — weak с явной проверкой объекта. Он предотвращает утечку памяти и корректно учитывает, что операция может завершиться после уничтожения владельца.
Ответ: Нет. В capture list копируется ссылка, а не экземпляр класса. Захваченное значение и исходная ссылка указывают на один объект, поэтому изменение его изменяемого свойства будет видно из обоих мест. Независимую копию нужно создавать явно, если это предусмотрено самим типом.
Ответ: При создании замыкания, а не при каждом его вызове. Поэтому capture list можно использовать для фиксации результата вычисления или текущего состояния зависимости. Это отличается от захвата внешней переменной без списка, когда замыкание может обращаться к актуальному захваченному хранилищу.
unowned не является просто более эффективным вариантом weak?Ответ: Эти ссылки выражают разные гарантии. Weak допускает, что объект исчезнет раньше замыкания, и автоматически становится nil; unowned утверждает, что объект будет существовать при каждом обращении. Поэтому unowned устраняет optional-проверку, но при нарушении гарантии вызывает аварийное завершение, а не безопасно возвращает отсутствие объекта.