Интервью
November 4

Как добавить weak-переменные в массив?

👋 Вопрос о том, почему в языке Swift невозможно напрямую добавлять weak-переменные в стандартные коллекции, такие как массивы, часто возникает на собеседованиях для разработчиков.

Этот аспект языка Swift подчеркивает одну из его ключевых особенностей — управление памятью и ссылочной семантикой.

Проблема с добавлением слабых ссылок в массив заключается в том, что weak-переменные могут автоматически обнуляться при деинициализации объектов, на которые они ссылаются. Это приводит к неопределенности: массив не сможет корректно обрабатывать исчезновение значений, потенциально оставляя нас с неполными или даже некорректными данными.

В этой статье рассмотрим способ добавления weak-переменных в массив.

Создание собственного контейнера

Надежный и рабочий вариант работы с weak-ссылками в коллекциях - создание собственного контейнера.

Создадим класс Weak, который будет содержать weak-свойство универсального типа.

class Weak<T: AnyObject> {
    weak var value: T?
    
    init(value: T) {
        self.value = value
    }
}

Теперь создадим класс WeakArray, который позволит обрабатывать объекты класса Weak, а также предоставит возможности добавления и получения элементов.

class WeakArray<T: AnyObject> {
    var list: [T] {
        elements.compactMap { $0.value }
    }
    
    private var elements: [Weak<T>] = []
    
    func append(_ element: T?) {
        guard let element = element else { return }
        
        let weakElement = Weak(value: element)
        elements.append(weakElement)
    }
}

Для демонстрации работы создадим класс Person, который будет подставляться вместо типа T.

class Person {
    let name: String
    
    init(name: String) {
        self.name = name
    }
}

Пример использования

Теперь приведем пример использования созданного контейнера:

// Пример использования
var weakArray = WeakArray<Person>()

var person1: Person? = Person(name: "Ivan")
var person2: Person? = Person(name: "Artem")

weakArray.append(person1)
weakArray.append(person2)

print(weakArray.list.map { $0.name })

person1 = nil // удаление объекта

print(weakArray.list.map { $0.name })

После выполнения кода, можно увидеть, что после обнуления одного из объектов, массив корректно обновляется и отображает существующие элементы.

["Ivan", "Artem"]
["Artem"]

Понимание того, как эффективно работать с weak-переменными в коллекциях, поможет вам создавать более безопасные и эффективные приложения.

👍 Ставьте лайк, если хотите, чтобы подобные посты выходили чаще.