Почему в расширениях (extension) Swift нельзя хранить свойства (stored properties)?

Ответ

Расширения в Swift предназначены для добавления новой функциональности существующим типам, но не могут добавлять stored properties. Это ограничение связано с тем, что stored properties требуют выделения дополнительной памяти в структуре экземпляра, а расширения не могут изменять макет памяти существующего типа после его компиляции.

Почему это важно?

  • Безопасность и предсказуемость: Гарантирует, что расширение не нарушит работу существующего кода, изменив размер или расположение типа в памяти.
  • Производительность: Value-типы (структуры, перечисления) копируются по значению. Добавление stored property через расширение потребовало бы создания новой, несовместимой версии типа.

Альтернативы для хранения данных:

  1. Вычисляемые свойства (Computed Properties):
    extension UIView {
    var cornerRadius: CGFloat {
        get { layer.cornerRadius }
        set { layer.cornerRadius = newValue }
    }
    }
  2. Ассоциированные объекты (Associated Objects): Работает только для классов, наследующихся от NSObject. Использует Objective-C runtime.
    
    import ObjectiveC

extension UIView { private enum AssociatedKeys { static var customTag = "customTag" }

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

}


3. **Протоколы с реализацией по умолчанию:** Для добавления поведения, а не состояния.

Ответ 18+ 🔞

А, слушай, смотри, вот эта вся хуйня с расширениями в Swift — она, конечно, мощная, но с одним огромным «но», блядь. Нельзя просто так взять и добавить stored property. Вообще нихуя. Это как прийти в гости и начать стену ломать, чтобы шкаф поставить — хозяева охуеют.

А почему, спрашивается, такая жесть?

  • Стабильность, ёпта: Представь, что у тебя структура Point с x и y. Всё летает. А потом какое-то ебучче расширение из другой либы добавляет туда z. И всё, пиздец, все экземпляры, созданные до этого, теперь битые — у них в памяти места под z нет! Компилятор такого не позволяет, и правильно делает, сука.
  • Скорость: Value-типы (структуры, перечисления) копируются молниеносно, потому что размер известен на этапе компиляции. Добавь stored property — и пошла пляска с бубном, размер плавает. Нахуй надо?

Но если очень хочется, а нельзя, что делать?

  1. Вычисляемые свойства — наш бро: Они не хранят нихуя, а просто делают вид. Идеально для обёрток над уже существующим дерьмом.

    extension UIView {
    var cornerRadius: CGFloat {
        get { layer.cornerRadius }
        set { layer.cornerRadius = newValue }
    }
    }

    Вот видишь? Никакого нового поля, просто удобный доступ к старому. Красота, блядь.

  2. Ассоциированные объекты — чёрная магия для Objective-C наследников: Это как привязать к объекту записку на ниточке. Работает только для классов, которые от NSObject произошли. Runtime, ёбана!

    
    import ObjectiveC

extension UIView { private enum AssociatedKeys { static var customTag = "customTag" }

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

}


Выглядит страшновато, но работает. Главное — не увлекаться, а то превратишь код в помойку.

3. **Протоколы с дефолтной реализацией — для умных:** Если нужно добавить поведение, а не состояние. Типа, «все, кто подписан на этот протокол, могут вот эту хуйню делать». Чисто, элегантно, без костылей.

Короче, Swift — не Python, тут просто так в runtime структуру не расширишь. И слава богу, а то был бы пиздец, а не язык.