@State
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper public struct State<Value> : DynamicProperty {
public init(wrappedValue value: Value)
public init(initialValue value: Value)
public var wrappedValue: Value { get nonmutating set }
public var projectedValue: Binding<Value> { get }
}
var 로 선언되어야함. private 으로 사용하는것 권고. (single source of truth)
SwiftUI 는 State 로 선언된 모든 프로퍼티의 스토리지를 관리.
State 변수값이 변하면 view 의 appearance 를 무효화하고, body 를 다시 계산한다.
State 로 선언된 instance 는 value 자체가 아님. 값에 접근시 value 프로퍼티 사용해야 함.
특정 view 에 속하고, 외부에서 절때 접근하면 안되는 간단한 프로퍼티 선언시에 적합.
아래로 선언해도 filteredLandmarks 변화 detect 해 view 뿌림.
@State private var showFavoritesOnly = true
var filteredLandmarks: [Landmark] {
landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
}
}
@State 프로퍼티는 항상 private 으로 선언하고, 가장 상위뷰에서 @State 를 관리할 것.
(외에서 initialized 되는것을 방지하기 위함)
자식 뷰에 데이터를 넘길 땐,
read-only 로 바로 전달하거나 read-write 을 위해선 binding 형태로 전달해야한다.
read-write 이 가능한 binding 형태에서만 부모뷰의 뷰를 업데이트할 수 있다.
@Binding
read & write
State 변수를 다른 뷰에 전달할 때 사용. $ 를 사용해 Binding 을 얻을 수 있음.
State 변수가 변경되면 @Binding 변수에서 인지하고 바로 뷰에 반영.
외부에서 접근해야하기 때문에 private 사용하지 않음.
You use the $ prefix to access a binding to a state variable, or one of its properties.
$ prefix 는 binding(projectedValue) 접근시 사용.
var projectedValue: Binding<Value>
wrappedValue, projectedValue
protocol ObservableObject: AnyObject
실제로 값이 변경되기 전에 신호를 주는 objectWillChange Publisher 를 제공한다.
해당 프로토콜을 채택한 class 의 instance 는 값이 변경되면 뷰가 업데이트 된다.
// 방법 1)
final class CounterViewModel: ObservableObject {
@Published var count = 0
func incrementCounter() {
count += 1
}
}
// 방법 2)
// 여러값을 변경 한 후, 수동으로 신호를 쏘고 싶을 때 유용.
final class CounterViewModel: ObservableObject {
private(set) var count = 0
func incrementCounter() {
count += 1
// ObservableObject 가 제공하는 objectWillChange 로 직접 신호를 보낼 수 도 있다.
objectWillChange.send()
}
}
@Published
ObservableObject 내에서 property 를 선언할 때 사용.
해당 속성이 업데이트 될 때 뷰를 업데이트 시킴.
@ObservedObject
ObservableObject 를 구독하고 값이 업데이트 될 때 뷰를 갱신.
여러 프로퍼티 및 메소드가 있거나 여러 view 에서 공유할 수 있는 커스텀 타입이 있는 경우 State 대신 사용.
아래처럼 ViewModel 클래스 인스턴스를 @ObservedObject 로 선언해 ViewModel 내의 @Published 프로퍼티를 감지할 수 있다.
final class CounterViewModel: ObservableObject {
@Published var count = 0
func incrementCounter() {
count += 1
}
}
struct CounterView: View {
@ObservedObject var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count is: \(viewModel.count)")
Button("Increment Counter") {
viewModel.incrementCounter()
}
}
}
}
@StateObject
ObservableObject 를 구독하고 값이 업데이트 될 때 뷰를 갱신.
사용시 @State 처럼 private 으로 사용하면 됨.
StateObject 와 달리 STate 는 항상 선언시 default value 로 initialized 되어있어야 한다.
SwiftUI 는 해당 모델의 instance 를 단 한번만 생성한다.
(= 뷰가 갱신되어도 instance 를 새로 생성하지 않음. 단, view 자체가 새로 생성되는 케이스는 제외)
@ObservedObject vs @StateObject
@StateObject 는 @ObservedObject 와 달리 view 의 body 가 재구성되어도 파괴되지 않음.
SwiftUI view 가 재구성될 가능성이 있는 경우 @ObservedObject 를 쓰는것은 안전하지 않음.
단, @StateObject 를 다량 사용시 여러군데에서 객체의 라이프사이클을 관리하게 됨.
(Apple 권고사항)
최초 초기화 시에는 StateObject 를 사용하고, 이미 객체화된 것을 넘겨 받을 땐 ObservedObject 를 사용.
@EnvironmentObject
ObservableObject 를 구독하고 값이 업데이트 될 때 뷰를 갱신.
reference 타입.
모든 view 에서 읽을 수 있는 shared 데이터.
프로퍼티가 변경되면 EvironmentObject 가 바인딩되고 있는 모든 view 가 자동 업데이트 됨.
단하나의 인스턴스만 사용될 수 있다.
.environmentObject(:_) 로 적용 가능.
@Environment
value 타입. (String, Int, Struct...)
key-value.
기본 제공되는 Environment 프로퍼티가 있다.
@Environment(\.locale) var locale: Locale
.environment() 로 적용 가능.
struct 로 EnvironmentKey 를 선언하면 custom 한 Environment 선언도 가능하다.
struct SunlightKey: EnvironmentKey {
static var defaultValue: Double = 1.09
}
extension EnvironmentValues {
var sunlight: Double {
get { self[SunlightKey.self] }
set { self[SunlightKey.self] = newValue }
}
}
@Environment(\.sunlight) var sunlight // 이렇게 사용 가능.
@Observable (iOS 17.0+)
Observable() 매크로
SwiftUI 는 observable 프로퍼티가 변경되거나 body 에서 property 를 직접 읽을때에만 view 를 갱신시킨다.
@Bindable (iOS 17.0+)
body 프로퍼티 내에서 Bindable 래퍼로 감싸 사용
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
'iOS' 카테고리의 다른 글
[iOS] Git 명령어 (0) | 2023.11.28 |
---|---|
[iOS] 공부 링크 (ing...) (0) | 2022.02.07 |
[iOS] Rendering (0) | 2020.12.31 |
[iOS] Swift 기본 문법 (YouTube - yagom) (0) | 2020.10.26 |
[iOS] Nine-Patch, 둥근모서리 이미지 소스 사용하기 (0) | 2020.10.20 |