Можно ли добавить хранимое свойство (stored property) в расширение (extension) в Swift?

«Можно ли добавить хранимое свойство (stored property) в расширение (extension) в Swift?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, напрямую добавить хранимое свойство (stored property) в расширение (extension) в Swift нельзя. Расширения предназначены для добавления функциональности, а не для хранения состояния.

Что МОЖНО добавить в extension:

  • Вычисляемые свойства (computed properties)
  • Методы
  • Инициализаторы (только convenience)
  • Сабскрипты
  • Вложенные типы

Пример вычисляемого свойства (разрешено):

extension Double {
    var km: Double { return self * 1000.0 } // Вычисляется при каждом обращении
    var cm: Double { return self / 100.0 }
}
let distance = 5.km // 5000.0

Обходные пути для хранения состояния:

1. Ассоциированные объекты (Objective-C runtime) Позволяют привязать значение к объекту, но работает только с классами, наследующими от NSObject.

extension UIView {
    private struct AssociatedKeys {
        static var customIdentifier = "customIdentifier"
    }

    var customIdentifier: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.customIdentifier) as? String
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.customIdentifier, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

2. Использование глобальной словарной таблицы (с осторожностью)

private var storedProperties = [ObjectIdentifier: Any]()

extension MyClass {
    var myProperty: Int {
        get { storedProperties[ObjectIdentifier(self)] as? Int ?? 0 }
        set { storedProperties[ObjectIdentifier(self)] = newValue }
    }
}

3. Наследование или композиция (предпочтительный способ)

// Вместо extension, создайте подкласс
class EnhancedView: UIView {
    var customStoredProperty: String = ""
}

// Или используйте композицию
struct ViewWrapper {
    let view: UIView
    var customStoredProperty: String
}

Вывод: Если вам нужно хранить состояние, расширение — неправильный инструмент. Рассмотрите редизайн через подкласс, композицию или (в крайнем случае) ассоциированные объекты.