iOS 응용 (SwiftUI)
[iOS - SwiftUI] @State를 사용하면 mutating 없이도 수정이 가능한 원리 (@State 직접 구현해보기)
jake-kim
2024. 7. 19. 01:32
@State를 사용하면 mutating 없이도 사용이 가능
- 아래처럼 @State를 프로퍼티에 붙여서 사용하면 change()함수에서 mutating 키워드가 없더라도 문제없이 동작
struct MyStruct {
@State
var val = 0
func change() {
val = 0
}
}
- struct이기 때문에 값을 변경하려면 원래 mutating키워드가 필요하지만 @State를 사용하면 mutating 없이 사용이 가능
struct MyStruct {
var a1 = 0
func change() {
a1 = 2 // Cannot assign to property: 'self' is immutable
}
}
- computed property, 일반적인 property wrapper모두 mutating이 필요함
struct MyStruct {
@DefaultValue(wrappedValue: 0, defaultValue: 18)
var age: Int
var a1 = 0
var a2: Int {
get { a1 }
set { a1 = newValue }
}
func change() {
age = 1 // Cannot assign to property: 'self' is immutable
a1 = 2 // Cannot assign to property: 'self' is immutable
a2 = 3 // Cannot assign to property: 'self' is immutable
}
}
@propertyWrapper
struct DefaultValue<T> {
private var value: T
private let defaultValue: T
init(wrappedValue: T, defaultValue: T) {
self.value = wrappedValue
self.defaultValue = defaultValue
}
var wrappedValue: T {
get { return value }
set { value = newValue }
}
var projectedValue: T {
get { return defaultValue }
}
}
@State를 사용하면 mutating이 없어도 되는 이유
- @State는 property wrapper인데, property wrapper 내부에서 관리하는 value를 reference type으로 설정하면 가능
- SwiftUI의 @State처럼 만들면 아래처럼 property wrapper 의 value가 class타입으로 정의
private class StateStorage<Value>: ObservableObject {
@Published var value: Value
init(initialValue: Value) {
self.value = initialValue
}
}
@propertyWrapper
struct SimpleState<Value>: DynamicProperty {
@ObservedObject private var stateStorage: StateStorage<Value>
init(wrappedValue: Value) {
self.stateStorage = StateStorage(initialValue: wrappedValue)
}
var wrappedValue: Value {
get { stateStorage.value }
nonmutating set { stateStorage.value = newValue }
}
var projectedValue: Binding<Value> {
Binding(
get: { self.wrappedValue },
set: { self.wrappedValue = $0 }
)
}
}
- 직접 만든 @SimpleState를 사용하면 mutating이 없어도 에러 없이 사용가능
struct MyStruct {
@SimpleState
var a3 = 0
func change() {
a3 = 4
}
}