Swift의 Property Wrapper(프로퍼티 래퍼) 정의와 사용법 Swift의 Property Wrapper(프로퍼티 래퍼)로 프로퍼티를 정의하고 사용하는 방법을 배워보세요.
Property Wrapper는 Class 또는 Struct 인스턴스의 프로퍼티에 값을 할당할 때 유효성 검사를 하기 위해 게터(getter)와 세터(setter), 연산 프로퍼티(computed property)를 추가하는 것을 캡슐화하여 코드를 간결하고 재사용 가능하게 합니다.
Property Wrapper는 @propertyWrapper 키워드를 사용해 정의하며, wrappedValue라는 필수 속성을 포함합니다.
Property Wrapper를 정의하는 방법은 다음과 같습니다.
@propertyWrapper
struct Capitalized {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.capitalized }
}
init ( wrappedValue : String ) {
self .wrappedValue = wrappedValue
}
}
위에서 사용한 @Capitalized을 사용하면 속성 값을 자동으로 대문자로 변환합니다.
struct Person {
@Capitalized var name: String
}
let person = Person ( name : "john" )
print (person.name) // John
사용자 입력값 검증에 활용할 수 있습니다.
@propertyWrapper
struct Clamped < Value : Comparable > {
private var value: Value
private let range: ClosedRange < Value >
var wrappedValue: Value {
get { value }
set { value = min ( max (newValue, range.lowerBound), range.upperBound) }
}
init ( wrappedValue : Value , range : ClosedRange < Value >) {
self . range = range
self . value = min ( max (wrappedValue, range.lowerBound), range.upperBound)
}
}
struct Settings {
@Clamped (range : 0 ... 100 ) var brightness: Int = 50
}
var settings = Settings ()
settings.brightness = 120
print (settings.brightness) // 100
값이 변경될 때마다 기록을 남길 수 있다.
@propertyWrapper
struct Logged < Value > {
private var value: Value
var wrappedValue: Value {
get { value }
set {
print ( "Value changed from \(value) to \(newValue) " )
value = newValue
}
}
init ( wrappedValue : Value ) {
self . value = wrappedValue
}
}
struct Logger {
@Logged var action: String
}
var logger = Logger ( action : "Start" )
logger.action = "Pause"
// Value changed from Start to Pause
logger.action = "Stop"
// Value changed from Pause to Stop
값을 캐싱하여 계산 비용을 줄일 수 있습니다.
@propertyWrapper
class Cached < Value > {
private var value: Value ?
private let computation: () -> Value
var wrappedValue: Value {
if let value = value {
return value
} else {
let computed = computation ()
value = computed
return computed
}
}
init ( wrappedValue : @escaping () -> Value ) {
self .computation = wrappedValue
}
}
struct DataManager {
@Cached { expensiveCalculation () } var cachedValue: Int
}
func expensiveCalculation () -> Int {
print ( "Expensive calculation performed" )
return 42
}
var manager = DataManager ()
print (manager.cachedValue) // Expensive calculation performed \n 42
print (manager.cachedValue) // 42