[SwiftUI] Property Wrapper

Judy·2023년 7월 21일
0

iOS

목록 보기
27/28

@State

SwiftUI에서 관리하는 값을 읽고 쓸 수 있는 속성 래퍼

  • View 내부에서 사용되며 해당 프로퍼티의 값이 변경되면 값에 의존하는 뷰를 업데이트
  • private으로 선언되어 init으로 초기화되는 것을 방지하고, 외부에서 사용되지 않음
  • SwiftUI가 해당 속성의 값을 관리하여 변화를 감지
  • 상태의 기본 값에 접근하려면 wrappedValue 속성 사용
  • ❗️클래스와 같은 참조 타입을 저장해야 하는 경우 StateObject를 사용
  • 하위 뷰에 전달하여 저장된 값을 수정하려 한다면 Binding을 전달 → 속성 앞에 $를 붙이면 바인딩을 가져올 수 있음
  • State

예시

struct PlayButton: View {    
	@State private var isPlaying: Bool = false // Create the state.
    
	var body: some View {       
		 Button(isPlaying ? "Pause" : "Play") { // Read the state.            
			isPlaying.toggle() // Write the state.        
		}    
	}
}

@StateisPlaying이 변경 ~~> 버튼의 레이블 변경

@Binding

source of truth가 소유한 값을 읽고 쓸 수 있는 속성 래퍼

  • 데이터를 직접 저장하는 대신 프로퍼티를 다른 뷰에 저장된 데이터에 연결
  • 상위 뷰에서 @State 프로퍼티 선언 → 하위 뷰에서 @Binding으로 연결
  • @State로 선언된 속성을 다른 뷰에서 사용해야 할 때 사용
  • 바인딩받은 뷰는 바인딩된 프로퍼티를 읽고 쓰기 및 외부 데이터의 변경 사항에 응답 가능
  • Binding

예시

struct PlayerView: View {    
	@State private var isPlaying: Bool = false

    var body: some View {          
		PlayButton(isPlaying: $isPlaying) // Pass a binding.          
	}
}


struct PlayButton: View {    
	@Binding var isPlaying: Bool

    var body: some View {        
		Button(isPlaying ? "Pause" : "Play") {            
			isPlaying.toggle()        
		}    
	}
}

상위 뷰(PlayerView)에서 전달한 @State를 하위 뷰(PlayButton)에서 @Binding으로 사용

@StateObject

ObservableObject를 인스턴스화하는 속성 래퍼

  • ObservableObject에 적용된다는 점을 제외하면 @State와 유사
  • 참조 타입(클래스)에 적용되며 @Published 프로퍼티가 변경될 때마다 SwiftUI에 알림
  • 하위 뷰로 전달하거나 environmentObject를 통해 전달할 수 있음
  • 적용 버전: iOS 14+, iPadOS 14+, watchOS 7+, macOS 10.16+ etc
  • StateObject

예시

class DataModel: ObservableObject {    
	@Published var name = "Some Name"    
	@Published var isEnabled = false
}

struct MyView: View {    
	@StateObject private var model = DataModel() // Create the state object.

    var body: some View {        
		Text(model.name) // Updates when the data model changes.        
		MySubView()            
		.environmentObject(model)    
	}
}
  • ObservableObject로 구현된 DataModel 클래스 타입에 적용한 @StateObject
  • @Publishedname, isEnabled가 변경되면 뷰가 업데이트

1) ObservableObject

publisher가 있는 타입을 나타내는 프로토콜

  • @Published 프로퍼티가 변경되기 전 변경된 값을 내보냄
  • ObservableObject

2) @Published

변경 시 publisher를 보낼 프로퍼티를 표시

  • $ 오퍼레이터를 통해 publisher에 접근
  • 클래스의 프로퍼티에 사용
  • Published

@ObservedObject

ObservableObject를 구독하고 ObservableObject가 변경될 때마다 뷰를 무효화하는 속성 래퍼

  • 뷰가 생성하거나 소유하지 않은 외부 참조 타입에 사용
  • ObservableObject를 준수하는 타입을 사용하고 변경될 때마다 뷰를 업데이트하려는 경우 사용
  • 자체로 생성하지 않은 점을 제외하면 @StateObject와 유사
  • 일반적으로 StateObject를 하위 뷰로 전달하기 위해 사용
  • EnvironmentObject와 달리 주입해서 사용해야 함
  • ObservabledObject

예시

struct MyView: View {    
	@StateObject private var model = DataModel()

    var body: some View {        
		Text(model.name)       
		 MySubView(model: model)    
	}
}

struct MySubView: View {    
	@ObservedObject var model: DataModel
    
	var body: some View {       
		Toggle("Enabled", isOn: $model.isEnabled)  
	}
}

ObservableObject인 DataModel 타입을 상위 뷰(MyView)에서 주입받아 사용

@EnvironmentObject

부모 또는 조상 뷰에서 제공하는 ObservableObject에 대한 속성 래퍼

  • 부모(조상)에서 제공하는 ObservableObject에 대한 wrapper
  • 뷰 간 데이터 공유
  • 별도로 값을 전달해주지 않아도 상속받는 부모로부터 함께 적용됨
  • 최상위 뷰에서 할당해준 후 environmentObject(_:) 수정자를 호출하여 설정하면 모든 뷰에서 사용 가능
  • EnvironmentObject

예시

struct MyApp: App {    
	@StateObject private var model = DataModel()
    
	var body: some Scene {        
		WindowGroup {
            ContentView()
                .environmentObject(model)
        }
	}
}


struct MyView: View {    
	@EnvironmentObeject private var model: DataModel

    var body: some View {        
		Text(model.name)       
		 MySubView(model: model)    
	}
}
profile
iOS Developer

0개의 댓글