Вопрос проверяет понимание механизма управления памятью в Swift и умение использовать слабые ссылки для предотвращения циклов сильных ссылок в коллекциях.
В Swift управление памятью осуществляется через автоматический подсчёт ссылок (ARC). Циклы сильных ссылок, когда два объекта удерживают друг друга, приводят к утечкам памяти. Слабые ссылки (weak references) — один из инструментов для их разрыва. Они не увеличивают счётчик ссылок ARC, поэтому, когда на объект остаются только слабые ссылки, он может быть освобождён.
Есть два основных способа создать коллекцию со слабыми ссылками:
NSMapTable позволяет явно указать, что значения должны храниться как слабые ссылки. Когда объект-значение освобождается, соответствующая запись в таблице автоматически удаляется.
import Foundation
// Создаём таблицу со слабыми значениями
let weakMap = NSMapTable(
keyOptions: .strongMemory,
valueOptions: .weakMemory
)
let key = "someKey" as NSString
let object = MyClass()
weakMap.setObject(object, forKey: key)
// object может быть освобождён, если больше нет сильных ссылок
// Проверка:
if let retrievedObject = weakMap.object(forKey: key) {
print("Объект жив: \(retrievedObject)")
} else {
print("Объект был освобождён")
}Создаём универсальный класс-обёртку, который хранит слабую ссылку. Затем используем массив таких обёрток.
class WeakReference {
weak var value: T?
init(value: T) {
self.value = value
}
}
class WeakCollection {
private var storage: [WeakReference] = []
func append(_ element: T) {
// Очищаем "мёртвые" ссылки перед добавлением
compact()
storage.append(WeakReference(value: element))
}
var allObjects: [T] {
compact()
return storage.compactMap { $0.value }
}
private func compact() {
storage = storage.filter { $0.value != nil }
}
}
// Использование
let collection = WeakCollection()
let vc = UIViewController()
collection.append(vc)
print(collection.allObjects.count) // 1
// Если vc освободится, после вызова allObjects массив будет пустым.Коллекции со слабыми ссылками часто используются для реализации паттернов вроде Observer или для хранения списков делегатов, где нежелательно, чтобы коллекция удерживала объекты и мешала их освобождению. Например, менеджер уведомлений может хранить слабые ссылки на своих подписчиков.
Вывод: Используйте коллекции со слабыми ссылками в Swift, когда вам нужно отслеживать набор объектов, но вы не хотите влиять на их время жизни и предотвращаете циклы удержания. NSMapTable удобен для словарей, а кастомная обёртка — для более гибкой работы с массивами в чистом Swift.