Ответ
Да, можно. Это мощная техника для добавления требований протокола и реализации по умолчанию через условные расширения.
1. Добавление соответствия протоколу с реализацией по умолчанию
protocol Displayable {
var displayName: String { get }
}
protocol Identifiable {
var id: UUID { get }
}
// Расширяем Identifiable, добавляя соответствие Displayable
// только для типов, которые уже соответствуют Identifiable
extension Identifiable {
var displayName: String {
return "ID: (id.uuidString.prefix(8))"
}
}
// Теперь любой тип, соответствующий Identifiable,
// автоматически получает реализацию Displayable
struct User: Identifiable {
let id = UUID()
// displayName доступен автоматически
}
let user = User()
print(user.displayName) // "ID: A1B2C3D4"
2. Условные расширения с where-ограничениями
protocol Savable {
func save()
}
// Добавляем соответствие Savable только для Collection,
// элементы которой соответствуют Codable
extension Collection where Element: Codable {
func save() {
let encoder = JSONEncoder()
if let data = try? encoder.encode(self) {
// Сохранение данных
UserDefaults.standard.set(data, forKey: "collection")
}
}
}
// Теперь массив Codable объектов получает метод save()
struct Item: Codable {}
let items: [Item] = [Item(), Item()]
items.save() // Работает!
Ключевые преимущества:
- Повышение переиспользуемости кода
- Избегание дублирования реализации
- Точечное добавление функциональности только нужным типам
- Поддержка протокол-ориентированного дизайна
Ответ 18+ 🔞
А, ну ты смотри какой, блядь, умник подъехал! Хочешь в extension хранимое свойство запихнуть, да? Ну, дружок, держи свои штаны — нихуя не выйдет!
Это, блядь, фундаментальное ограничение Swift, ёпта! Расширение — оно как бы дополняет, а не ломает структуру памяти типа. Представь, что ты пришёл в гости и начал в чужой квартире несущие стены ломать. Тебе же по ебалу дадут, правильно? Вот и Swift так же.
Что МОЖНО делать в extension, чтобы не выглядеть полным мудаком:
-
Вычисляемые свойства (computed properties) — это твой лучший друг, если мозгов хватает.
extension UIView { var isVisible: Bool { get { return !isHidden && alpha > 0 } set { isHidden = !newValue } } }Вот видишь? Никакой магии, просто логика. Не хранит нихуя, а работает.
-
Статические свойства — тоже ок.
extension UIColor { static var customRed: UIColor { return UIColor(red: 0.9, green: 0.1, blue: 0.1, alpha: 1.0) } }Типа константы, блядь. Красота.
А теперь, сука, обходные пути для самых настойчивых распиздяев:
1. Ассоциированные объекты — но только для классов, которые от NSObject торчат, как хуй из штанов.
import ObjectiveC
extension UIView {
private struct 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)
}
}
}
// Использование
let view = UIView()
view.customTag = "ImportantView"
Вот это уже похоже на хранимое, да? Но это чисто Objective-C магия, блядь. Swift так не умеет из коробки.
2. Обёртка через вычисляемое свойство — для тех, кто боится Objective-C как чёрт ладана.
class Storage {
static let shared = Storage()
private var values: [ObjectIdentifier: Any] = [:]
func setValue<T>(_ value: T, for key: ObjectIdentifier) {
values[key] = value
}
func getValue<T>(for key: ObjectIdentifier) -> T? {
return values[key] as? T
}
}
extension UIView {
var persistentData: String? {
get {
let key = ObjectIdentifier(self)
return Storage.shared.getValue(for: key)
}
set {
let key = ObjectIdentifier(self)
Storage.shared.setValue(newValue, for: key)
}
}
}
Ну, типа храним, но на самом деле — нет, блядь. Всё в отдельной словарь засунули. Костыль, конечно, но работает.
Итог, ёпта:
- Хочешь по-честному — добавляй свойства в основное объявление типа, а не выёбывайся.
- Расширения — для поведения, а не для изменения скелета.
- Ассоциированные объекты — это как грязные носки под кроватью: работает, но пахнет.
Вот так вот, блядь. Разобрался? Иди теперь делай, а не вопросы ебаные задавай!