SwiftUI 튜토리얼 5편 — @State, @Binding, @ObservedObject

다양한 바인딩 방법에대해 알아보기

Harry The Great
해리의 유목코딩

--

지금까지는 간단한 UI를 만드는 순서로 진행되었습니다. 이번 편은 SwiftUI의 데이터 바인딩 처리에 대해 배워보겠습니다. 사용자에게 데이터를 어떻게 보여주느냐는 UI에서 가장 핵심적인 부분입니다. 먼저 간단한 예제를 보겠습니다.

이전에 제가 State는 뷰가 접근 가능하도록 값을 가지고 있는 프로퍼티 래퍼(Property Wrapper)이라고만 말씀드렸는데 조금만 더 깊게 들어가자면, 프로퍼티 래퍼는 Swift 5.1부터 추가된 어노테이션입니다. 프로퍼티 래퍼는 쉽게 말해 사용자가 별도의 코딩 없이 어노테이션만 선언해도 뷰에서 수정이나 읽기가 가능하도록 캡슐화를 대신해줍니다. 자세한 내용은 이 링크를 클릭해주세요.

  • isToggleOn -> Bool값
  • $isToggleOn -> Binding<Bool>

$가 붙으면 프로퍼티 래퍼 자체를 받기때문에 안에 있는 WrapperValue 자체를 변경할 수 있습니다.

@State는 해당 View 외부로는 사용할 수가 없고 private 형태로 내부에서만 사용가능한데 이전에 뷰가 직접 가지고있는 값이라고 했지만 사실 엄밀히는 조금 다릅니다. 도식화를 시켜보면

View 외부의 내부메모리에 isPresented 값을 초기화 시키고있습니다. 그러다 Binding<T>의 WrapperValue값이 변동됨과 동시에 View는 사라지게됩니다.

그다음 뷰가 다시 만들어지며 변동된 값을 재 참조하는 방식으로 값이 유지가 됩니다.
만약 리스트뷰와 토글 뷰가 나뉘어 토글에 따라 리스트를 바꿔야 하는 경우처럼 두 개의 뷰가 동시에 하나의 State를 참조해야 하는 경우가 생길 수 있습니다. 이때 @Binding을 사용 용할 수 있습니다.

@Binding

단순히 @Binding 어노테이션으로 선언하여 초기화할 때 State값을 받는 것만으로 여러 개의 뷰가 동시에 State값을 참조할 수 있습니다. 하지만 State는 Toggle 유무와 같은 UI의 상태 값과 같은 아주 한정된 용도로만 사용하기를 권고하고 있는데 그 이유는 뷰 안에만 사용하는 메모리 공간이기 때문입니다. 만약 뷰 밖의 클래스에서 사용한다면? ObservableObejct를 사용할 수 있습니다.

@ObservableObject

별도의 클래스를 만든다음 ObservedObject 프로토콜을 상속받으면 SwiftUI에서 사용할 수 있습니다.

count 앞에 있는 Published어노테이션은 값이 변동되었을때 바로 View에게 즉각적으로 알려주는 Annotation입니다.

이제 View 안에서도 외부 클래스를 사용할 수 있습니다. 만약 @Published를 지우고 실행한다면 버튼을 눌러도 값은 바뀌지만 UI는 바뀌지 않습니다. 만약 즉각적으로 UI가 바뀌는것이 아닌 특정한 조건식에 의해 UI를 변동시킬 수도있습니다.

objectWillChange.send()는 SwiftUI에 값이 변동됐음을 알려주는 메서드로 위에서는 값이 5 단위일 때만 실행되기 때문에 이제 버튼을 눌렀을 때 5번씩 눌렀을 때만 텍스트가 바뀌게 됩니다.

@EnvironmentObject

EnviromentObject는 별도로 값을 전달해주지 않아도 상속받는 부모로부터 함께 적용되는 오브젝트입니다. 최상위뷰에 할당해주기위해 SceneDelegate.swift 파일로 이동해보겠습니다.

SceneDelegate 클래스의 Scene 메서드를보면 window.rootViewController에 UIHostringController를 이용하여 ContentView를 최상위뷰로 할당하고있습니다.

window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(CountRepo()))

enviromentObject 메서드를 붙여 CountRepo를 넘겨줍니다. 이제 자식뷰들에서 우리가 주입한 CountRepo를 사용할 수 있습니다.

최상위뷰에 envrioemntOjbect를 정해주었기때문에 하위 뷰들은 어디서든 EnviromentObject 어노테이션을 이용하여 값에 접근할 수 있습니다.

물론 최상위 뷰가 아닌 서브 뷰에도 enviromentObject를 할당할 수 있는데 부모 뷰로부터 자식 뷰로만 전달되기 때문에 위와 같이 형제 뷰인 ChildTextView와 ChildButtonView는 서로 값을 공유하지 않아 에러가 발생합니다.

--

--

Harry The Great
해리의 유목코딩

Android & IOS Developer 😀 미디움 이외에 스니펫이나 디버그노트로 활용하는 https://www.harrymikoshi.com/ 블로그도 운영하고있습니다.