Ответ
Property Wrapper — это механизм в Swift, который позволяет инкапсулировать стандартную логику работы с getter и setter свойства в переиспользуемый тип. Он «оборачивает» значение свойства, добавляя к нему дополнительное поведение при чтении и записи.
Синтаксис и компоненты:
- Атрибут
@propertyWrapper: Помечает структуру или класс как обертку. - Свойство
wrappedValue: Обязательное свойство, которое содержит логику get/set для обернутого значения. - Инициализатор: Может принимать начальное значение.
- Свойство
projectedValue(опционально): Предоставляет дополнительный API для обернутого свойства (доступ через$).
Пример: Обертка для автоматического триммирования строки.
@propertyWrapper
struct Trimmed {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue // Используется setter
}
}
// Использование
struct UserProfile {
@Trimmed var username: String
@Trimmed var email: String
}
var profile = UserProfile(username: " john_doe ", email: " email@example.com ")
print(profile.username) // "john_doe" (пробелы удалены)
print(profile.email) // "email@example.com" (пробел удален)
Пример с projectedValue (логирование изменений):
@propertyWrapper
struct Logged<Value> {
private var value: Value
private let name: String
var wrappedValue: Value {
get { value }
set {
print("Свойство '(name)' изменено: (value) -> (newValue)")
value = newValue
}
}
var projectedValue: Self { self } // Проецируем саму обертку
init(wrappedValue: Value, _ name: String = "") {
self.value = wrappedValue
self.name = name
}
}
struct Settings {
@Logged("volume") var volume: Double = 0.5
}
var settings = Settings()
settings.volume = 0.7 // В консоли: "Свойство 'volume' изменено: 0.5 -> 0.7"
let wrapper = settings.$volume // Доступ к самой обертке через projected value
Распространенные применения:
- Валидация и нормализация (как в
@Trimmed). - Синхронизация с UserDefaults (
@UserDefault). - Ограничение значений (
@Clamped(min: 0, max: 100)). - Ленивая инициализация (встроенный
@Lazy). - Thread-safe доступ к свойствам.
Итог: Property Wrapper — мощный инструмент для соблюдения принципа DRY, позволяющий выносить стандартную логику работы со свойствами в отдельные, тестируемые компоненты.
Ответ 18+ 🔞
А, property wrapper! Ну это ж просто пиздец какой-то удобный механизм, блядь! Сидишь такой, пишешь код, и каждый раз одно и то же — то строки триммировать, то в UserDefaults синхронизировать, то значения ограничивать. И вот ты уже, сука, двадцатый раз копипастишь эту хуйню, а потом смотришь — а что это за дичь? Property wrapper, ёпта!
Смотри, как это работает, блядь. Вместо того чтобы каждый раз в каждом свойстве писать одно и то же, ты эту логику в отдельную структуру засовываешь. А потом просто ставишь перед свойством собачку @ и имя этой структуры. И всё, блядь! Оно само работает!
Вот смотри, пример — обертка, которая строки от пробелов по краям чистит. Ну, classic, блядь:
@propertyWrapper
struct Trimmed {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue // Используется setter
}
}
Видишь? wrappedValue — это, блядь, святое. Без него нихуя не работает. Туда вся магия и зашита.
А потом используешь:
struct UserProfile {
@Trimmed var username: String
@Trimmed var email: String
}
var profile = UserProfile(username: " john_doe ", email: " email@example.com ")
print(profile.username) // "john_doe" (пробелы удалены, блядь!)
print(profile.email) // "email@example.com" (пробел удален, красота!)
Во, блядь! Засунул пользователю в имя пробелы, а они взяли и исчезли! Магия, сука! А ты даже не парился.
А бывает ещё projectedValue — это такая, блядь, дополнительная фича. Через доллар $ к ней обращаешься. Ну, например, чтобы саму обёртку наружу вытащить или ещё какую хуйню.
Вот, смотри, обёртка, которая логирует, когда значение меняется:
@propertyWrapper
struct Logged<Value> {
private var value: Value
private let name: String
var wrappedValue: Value {
get { value }
set {
print("Свойство '(name)' изменено: (value) -> (newValue)") // Во, бля, сообщение!
value = newValue
}
}
var projectedValue: Self { self } // Проецируем саму обертку, ёпта
init(wrappedValue: Value, _ name: String = "") {
self.value = wrappedValue
self.name = name
}
}
struct Settings {
@Logged("volume") var volume: Double = 0.5
}
var settings = Settings()
settings.volume = 0.7 // В консоли: "Свойство 'volume' изменено: 0.5 -> 0.7" — видишь, следит за тобой, сука!
let wrapper = settings.$volume // А вот и projected value через доллар, блядь!
И где это, блядь, применяется? Да везде, ёпта!
- Валидация и нормализация — как наш
@Trimmed, который строки подчищает. - Синхронизация с UserDefaults — сделал обёртку
@UserDefault, и она сама туда-сюда пишет, не надо мозг ебать. - Ограничение значений —
@Clamped(min: 0, max: 100), чтобы, блядь, значение не уехало за пределы. Хуй на гору не полезет. - Ленивая инициализация — да там встроенный
@Lazyуже есть, ленивая жопа. - Thread-safe доступ — чтобы с разных потоков не наебаться.
Короче, property wrapper — это, блядь, овердохуища полезная штука. Вместо того чтобы повторять один и тот же код как мудак, ты его в одном месте пишешь, а потом навешиваешь как декорацию. DRY принцип, блядь, в действии! Чисто, тестируемо, переиспользуемо. Ёперный театр, как же раньше без этого жили-то?