[Swift] - Property Wrappers

sai06266·2024년 2월 14일
0

Swift 문법

목록 보기
9/9

정의

Swift 자체에서 특정한 기능이나 패턴들을 재사용하기 위해서 속성 즉 프로퍼티에 적용할 수 있는 사용자 정의 속성, modifier

다양한 Property Wrappers

  1. @State
  2. @Binding
  3. ObsevableObect
  4. @Published
  5. @ObservedObject
  6. @StateObject
  7. @Environment
  8. @EnvironmentObject

@State

  • SwiftUI에서 상태를 처리하는 방법
  • 뷰의 상태를 저장하는 프로퍼티로 상태 관리 주체는 해당 뷰
  • 기본적으로 Private 선언이기에 다른 뷰와 값을 소통하려면 Binding을 이용
  • 값이 변경될 때마다 UI 업데이트
struct PlayButton:View{
	@State private var isPlaying:Bool = false
    
    var body: some View{
    	Button(isPlaying?"Pause":"Play"){
        	isPlaying.toggle()
        }
    }
}

@Binding

  • 뷰와 상태를 바인딩 하는 방법
  • 상위 @State 변수를 전달받아 하위 뷰에서 캐치해 변화 감지 및 연결
  • 상위 뷰와 하위 뷰에서 값을 공유할 때
  • Binding은 다른 뷰가 소유한 속성을 연결하기에 소유권 및 저장 공간이 없음
struct PlayerView: View{
	var episode: Episode
    @State private var isPlaying:Bool = false
    
    var body: some View{
    	VStack{
        	Text(episode.title)
            	.foregroundStyle(isPlaying?.primary:.secondary)
            PlayButton(isPlaying: $isPlaying) //binding
        }
    }
}

struct PlayButton:View{
	@Binding var isPlaying:Bool = false
    
    var body: some View{
    	Button(isPlaying?"Pause":"Play"){
        	isPlaying.toggle()
        }
    }
}

ObservableObject -> 클래스 프로토콜

  • 클래스 프로토콜로 관찰하는 어떠한 값이 변경되면 변경사항을 알려줌
  • 뷰에서 인스턴스 변화를 감시하기 위해 뷰모델 객체로 생성할 때 사용할 수 있음
class Contact: ObservableObject{
	@Published var name: String
    @Published var age: Int
    init(name: String, age: Int){
    	self.name = name
        self.age = age
    }
    func haveBirthday() -> Int{
    	age += 1
        return age
    }
}

let john = Contact(name:"John", age:24)
cancellable = john.objectWillChange
	.sink{ _ in
    	print("\(join.age) will change")
    }
print(john.haveBirthday())

@Published

  • ObservableObject를 구현한 클래스 내에서 프로퍼티 선언 시 사용
  • @Published로 선언된 프로퍼티를 뷰에서 관찰할 수 있음
  • ObservableObject의 objectWillChange.send() 기능을 @Published 프로퍼티가 변경되면 자동으로 호출

@ObservedObject

  • 뷰에서 ObservableObject 타입의 인스턴스 선언시 사용
  • ObservableObject의 값이 업데이트되면 뷰를 업데이트
class User: ObservableObject{
	@Published var age = 10
}

struct ContentView: View{
	@ObservedObject var user: User
   	var body: some View{
       	Button("Plus age"){
            user.age += 1
        }
    }
}

@StateObject

  • 뷰에서 ObservableObject 타입의 인스턴스 선언 시 사용
  • 뷰마다 하나의 인스턴스를 생성하며, 뷰가 사라지기 전까지 같은 인스턴스 유지
  • @ObservedObject의 뷰 렌더링 시 인스턴스 초기화 이슈 해결을 위한 방법
  • 매번 인스턴스가 새롭게 생성되는 것처럼 외부에서 주입 받는 경우가 아닌 최초 생성 선언 시에 @StateObject를 사용하는 것이 적절한 방법

@Environment

  • 미리 정의되어 있는 시스템 공유 데이터
  • 사용하려는 공유 데이터의 이름을 keyPath로 전달하여 사용
  • 시스템 공유 데이터는 가변하기에 var로 선언 필요
  • 뷰가 생성되는 시점에 값이 자동으로 초기화됨
struct ContentView: View{
	@Environment(\.colorScheme) var colorScheme
    
    var body: some View{
    	Text("Hello World")
        	.foregroundColor(colorScheme == .dark ? .white : .black)
    }
}

@EnvironmentObject

  • ObservableObject를 통해 구현된 타입의 인스턴스를 전역적으로 공유하여 사용
  • 앱 전역에서 공통으로 사용할 데이터를 주입 및 사용
class Info: ObservableObject{
	@Published var age = 10
}
@main
struct MyApp: App{
	var body: some Scene{
    	WindowGroup{
        	MainView()
            	.environmentObject(Info())
        }
    }
}
struct MainView: View{
	@EnvironmentObject var info: Info
    var body: some View{
    	Button(action: {
        	self.info.age += 1
        }) {
        	Text("Click Me for plus age")
        }
        SubView()
     }
}
struct SubView: View{
	@EnvironmentObject var info: Info
    var body: some View{
    	Button(action: {
        	self.info.age -= 1
        }) {
        	Text("Click Me for minus age")
        }
     }
}

0개의 댓글