[Swift] 상태

임클·2023년 3월 9일
0

Swift

목록 보기
27/37
post-thumbnail
post-custom-banner

들어가면서..

SwiftUI 기반의 iOS 프로그래밍 "닐 스미스 지음 / 황반석 옮김" 책에서 인용함

SwiftUI에서는 데이터와 사용자 인터페이스 내의 뷰 사이에 게시자(Publisher)와 구독자 (Subscriber)를 구축할 수 있다.

이를 위하여 SwiftUI는 상태 프로퍼티, Observable 객체, 그리고 Environment 객체를 제공하며, 이들 모두는 사용자 인터페이스의 모양과 동작을 결정하는 상태를 제공한다. SwiftUI에서 사용자 인터페이스 레이아웃을 구성하는 뷰는 코드 내에서 직접 업데이트하지 않는다.
그 대신, 뷰와 바인딩된 상태 객체가 시간이 지남에 따라 변하면 그 상태에 따라 자동으로 뷰가 업데이트된다.

상태 프로퍼티 (state property)

상태에 대한 가장 기본적인 형태이며, 뷰 레이아웃의 현재 상태(예를 들어, 토글 버튼이 활성화되었는지 여부, 텍스트 필드에 입력된 텍스트, 또는 피커 뷰에서의 현재 선택)를 저장하기 위해서만 사용된다. 상태 프로퍼티는 String이나 Int 값처럼 간단한 데이터 타입을 저장하기 위해 사용되며 @State 프로퍼티 래퍼를 사용하여 선언된다.

struct ContentView : View {

	@State private var sifiEnabled = true
    @State private var userName = ""
    
    var body : some View { ...}
}

상태 값은 해당 뷰에 속한 것이기 때문에 private 프로퍼티로 선언되어야 한다.

상태 프로퍼티 값이 변경되었다는 것은 그 프로퍼티가 선언된 뷰 계층구조를 다시 렌더링해야 한다는 SwiftUI 신호다. 즉, 그 계층구조 안에 있는 모든 뷰를 빠르게 재생성하고 표시해야 한다. 결국, 그 프로퍼티에 의존하는 모든 뷰는 어떤 식으로든 최신 값이 반영되도록 업데이트된다.

상태 프로퍼티를 선언했다면 레이아웃에 있는 뷰와 바인딩을 할 수 있다. 바인딩이 되어 있는 뷰에서 어떤 변경이 일어아면 해당 상태 프로퍼티에 자동으로 반영된다. 예를 들어, 토글 뷰와 위에서 선언한 불리언 타입의 wifiEnabled 프로퍼티가 바인딩되어서 사용자가 토글 뷰를 조작하면 SwiftUI는 새로운 토글 설정값으로 상태 프로퍼티를 자동으로 업데이트할 것이다.

상태 프로퍼티와의 바인딩은 프로피터 이름 앞에 '$'를 붙이면 된다. 다음의 예제에서 TextField 뷰는 사용자가 입력한 텍스트를 저장하는 데 사용하기 위해 userName이라는 상태 프로퍼티와 바인딩된다.

struct ContentView : View {
	
    @State private var wifiEnabled = true
    @State private var userName = ""
    
    var body : some View {
    	VStack{
        	TExtField("Enter user name " , text : $userName)
        }
    }
}

사용자가 TextField에 입력하게 되면 바인딩은 현재의 텍스트를 userName 프로퍼티에 저장할 것이다. 이 상태 프로퍼티에 변화가 생길 때마다 뷰 계층구조는 SwiftUI에 의해 다시 렌더링된다.

물론, 상태 프로퍼티에 값을 저장하는 것은 단방향 프로세스이다. 상태가 변하면 레이아웃에 있는 다른 뷰들도 변경된다. 다음의 예제에서 Text 뷰는 입력된 사용자의 이름을 반영하기 위하여 업데이트되어야 한다. 이 작업은 Text 뷰를 위한 콘텐트로 userName 상태 프로퍼티 값을 선언하면 된다.

var body : some View {
	VStack{
    	TextField("Enter user name ", text : $userName)
        Text(userName)
    }
}

사용자가 텍스트를 입력하면 Text 뷰는 사용자의 입력을 반영하기 위해 자동으로 업데이트 될 것이다. 여기서 주목해아 할 점은 userName 프로퍼티가 '$' 표시 없이 사용되었다는 것이다. 왜냐하면 이제는 상태 프로퍼티에 할당된 값(즉, 사용자에 의해 입력된 String 값)을 참조하려고 사용하기 때문이다.

마찬가지로, 앞서 설명한 Toggle 뷰와 wifiEnabled 상태 프로퍼티 간의 바인딩은 다음과 같이 구현할 수 있다.

var body : some View{
	VStack{
    	Toggle(isOn : $wifiEnabled){
        	Text("Enalbe Wi-Fi")
        }
        TextField("Enter user name", text :$userName)
        Text(userName)
        Image(systemName : wifiEnabled ? "wifi" : "wifi.slash")
    }
}

앞의 선언부에서 Toggle 뷰와 상태 프로퍼티 간의 바인딩이 구현되었다. 이 프로퍼티에 할당된 값은 어떤 이미지를 Image 뷰에 포함할지를 결정하기 위해 사용된다.

앞의 예제에서 Image 뷰는 systemName 이미지를 참조체를 이용한다. 이것은 SF Symbol 드로잉의 내장된 라이브러리에 접근할 수 있게 해준다. SF Symbol은 애플 플랫폼 용 앱을 개발할 때 사용할 수 있는 1,500개의 크기 조절이 가능한 벡터 이미지 모음이며, 애플의 샌프란시스코 시스템 폰트를 보완하기 위해 설계되었다.


상태 바인딩

상태 프로퍼티는 선언된 뷰와 그 하위 뷰에 대한 현재 값이다. 하지만, 어떤 뷰가 하나 이상의 하위 뷰를 가지고 있으며 동일한 상태 프로퍼티에 대해 접근해야 하는 경우가 발생한다. 예를 들어, 앞의 예제에 있는 와이파이 이미지 뷰가 하위 뷰로 분리되는 상황을 살펴보자.

.
.
	VStack{
    	Toggle(isOn : $wifiEnabled) {
        	Text("Enable wifi")
        }
        TextField("Enter user name", text : $userName)
	    WifiImageView()
    }
.
.

struct WifiImageView : View{
	
    var body : some View {
	    Image(systemName : wifiEnabled ? "wifi" : "wifi.slash")
    }
    
}

WifiIamgeView 하위 뷰는 여전히 wifiEnabled 상태 프로퍼티에 접근해야 한다. 하지만 분리된 하위 뷰의 요소인 Image 뷰는 이제 메인 뷰의 범위 밖이다. 다시 말해, WifiImageView 입장에서 보면 WifiImageView에 있는 wifiEnabled 프로퍼티는 정의되지 않은 변수인 것이다.

이 문제는 다음과 같이 @Binding프로퍼티 래퍼를 이용하여 프로퍼티를 선언하면 해결된다.

struct WifiImageVIew : View {
	@Binding var wifiEnabled : Bool
    
    var body : some View {
    	Iamge(systemName : wifiEnabled ? "wifi" : "wifi.slash")
    }
}

이제 하위 뷰가 호출될 때 상태 프로피티에 대한 바인딩을 전달하면 된다.

WifiImageView(wifiEnabled : $wifiEnabled)
profile
iOS를 공부하는 임클입니다.
post-custom-banner

0개의 댓글