상태, Observable 객체, 그리고 Enviroment 객체로 작업하기

Rio·2021년 7월 10일
0

IOS

목록 보기
6/10
post-thumbnail

☕️ SwiftUI

  • 데이터 주도 방식으로 앱을 개발
  • 사용자 인터페이스 내의 뷰들은 기본 데이터 변경에 따른 처리 코드를 작성하지 않아도 뷰가 업데이트된다
  • 데이터와 사용자 인터페이스 내의 뷰 사이에 게시자(publisher)구독자(subscriber)를 구축하여 가능
  • 이를 위해 SwiftUI는 상태 프로퍼티, Observable 객체, Environment 객체를 제공
  • 이들 모두 사용자 인터페이스의 모양과 동작을 결정하는 상태를 제공

🍶 상태 프로퍼티

  • 상태에 대한 가장 기본적인 형태
  • 뷰 레이아웃의 현재 상태를 저장
    - 토글 버튼 활성 유무, 텍스트 필드 입력된 텍스트 등..
  • String이나 Int 값처럼 간단한 데이터 타입을 저장
  • @State 프로퍼티 래퍼를 사용하여 선언
  • 상태 값은 해당 뷰에 속한 것이기에 priavte로 선언되어야 한다
  • "선언해준 상태 프로퍼티 값이 변경되었다?" -> 해당 프로퍼티가 선언된 뷰 계층구조를 다시 렌더링 해야한다!!
  • 즉, 프로퍼티에 의존하는 모든 뷰는 어떤 식으로든 최신 값이 반영되도록 업데이트되어야 한다
  • 상태 프로퍼티를 선언했다면 관련된 레이아웃에 있는 와 바인딩을 할 수 있다.
  • 바인딩 되어 있는 뷰에서 어떤 변경이 일어나면 해당 상태 프로퍼티에 자동으로 반영!
  • 상태 속성과의 바인딩은 프로퍼티 이름 앞에 '$'를 붙이면 된다.
struct Test04: View {
    
    @State private var wifiEnabled = true
    @State private var userName = ""
    
    var body: some View {
        VStack{
            Toggle(isOn: $wifiEnabled, label: {
                Text("Enable Wi-Fi")
            })
            Image(systemName: wifiEnabled ? "wifi":"wifi.slash").resizable().frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/, height: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/).foregroundColor(.red)
            TextField("Enter user name",text:$userName)
            Text(userName).font(.largeTitle)
        }
    }
}

🍹 systemName 이미지 참조체 : SF Symbol 드로잉의 내장된 라이브러리에 접근할 수 있게 한다. SF Symbol은 애플 플랫폼용 앱을 개발할 때 사용할 수 있는 많은 크기 조절이 가능한 벡터 이미지 모음

🤿 상태 바인딩

  • 상태 프로퍼티는 선언된 뷰와 그 하위 뷰에 대한 현재 값
  • But, 어떤 뷰가 하나 이상의 하위 뷰를 가지고 있으며 동일한 상태 프로퍼티에 접근하는 경우가 발생
  • @Binding 프로퍼티 래퍼를 이용하여 외부 뷰에서도 상태 프로퍼티 접근이 가능하다
  • 하위 뷰가 호출될 때 상태 프로퍼티에 대한 바인딩을 전달하면 된다
// 상태 바인딩
struct Test05: View {
    @State private var wifiEnable = true
    var body: some View {
        VStack{
            Toggle(isOn: $wifiEnable, label: {
                Text("wifi")
            })
            
            //이미지 뷰어를 외부로 정의
            //파라미터로 상태 속성을 보내준다
            WifiImageView(wifiEnable:$wifiEnable)
        }
    }
}

//이미지 뷰를 외부로 따로 선언
struct WifiImageView:View{
    //상태 바인딩
    @Binding var wifiEnable : Bool
    var body: some View{
        Image(systemName: wifiEnable ? "wifi" : "wifi.slash")
    }
}

🎯 Observable 객체

  • 상태 프로퍼티는 뷰의 상태를 저장하는 방법을 제공하며 해당 뷰에서만 사용 가능
  • 하위 뷰가 아니거나 상태 바인딩이 구현되어 있지 않은 다른 뷰는 접근 불가능
  • 상태 프로퍼티는 일시적인 것이여서 부모 뷰가 사라지면 그 상태도 소멸
  • Observable 객체는 여러 다른 뷰들이 외부에서 접근 할 수 있는 영구적인 데이터를 표현하기 위해 사용
  • 일반적으로 시간에 따라 변경되는 하나 이상의 데이터 값을 모으고 관리하는 역할
  • 타이머나 알림과 같은 이벤트를 처리하기 위해 사용될 수 있다
  • 게시된 프로퍼티(published property)로서 데이터 값을 게시(publish)
  • 게시자를 구독(subscribe)하여 게시된 프로퍼티가 변경될 때마다 업데이트
  • Combine 프레임워크 : 여러 게시자를 하나의 스트림으로 병합하는 것부터 게시된 데이터를 구독자 요구에 맞게 변형하는 것까지 다양한 작업을 수행하는 커스텀 게시자 구축 플랫폼을 제공
  • @Publish 프로퍼티 래퍼를 사용
// 간단한 observable 객체 선언
import Foundation
import Combine //Combime 프레임워크 import

class DemoData : ObservableObject{
    
    @Published var userCount = 0
    @Published var currentUser = ""
    
    init(){
        //데이터를 초기화하는 코드가 여기에 온다
        updateDate()
    }
    
    func updateDate(){
        // 데이터를 최신 상태로 유기하기 위한 코드가 여기에 온다
    }
}
  • 구독자는 위 구조체와 같은 observable 객체를 구독(접근)하기 위해서 @ObservedObject 프로퍼티 래퍼를 사용
  • 구독하게 되면 그 뷰 및 모든 하위 뷰가 상태 프로퍼티와 같이 게시된 프로퍼티에 접근하면 된다
struct Test06_Observable: View {
    //키워드 헷갈리지 않게 주의!!
    @ObservedObject var demoData : DemoData
    
    var body: some View {
        Text("\(demoData.currentUser),you are user number \(demoData.userCount)")
    }
}

struct Test06_Observable_Previews: PreviewProvider {
    static var previews: some View {
        Test06_Observable(demoData: DemoData())
    }
}

🎹 Enviroment 객체

  • Observable(구독) 객체는 특정 상태가 앱 내의 몇몇 SwiftUI 뷰에 사용되어야 할 경우에 가장 적합
  • 어떤 뷰에서 다른 뷰로 이동(navigation)하는데 이동될 뷰에서도 동일한 구독 객체에 접근해야 한다면, 이동할 때 대상 뷰로 구독 객체에 대한 참조체를 전달해야한다
  • 앱 내의 여러 뷰가 동일한 구독 객체에 접근시 복잡해짐
  • 이럴때는 Enviroment 객체를 사용하는 것이 더 합리적
  • Enviroment객체는 Observable 객체와 같은 방식으로 선언
  • 중요한 차이는 이 객체는 SwiftUI 환경에 저장되며, 뷰에서 뷰로 전달 필요 없고, 모든 뷰가 접근 할 수 있다
  • @Enviroment 객체를 구독해야하는 객체는 @ObservedObject 래퍼 대신 @EnviromentObject 프로퍼티 래퍼를 사용하여 참조하면 된다
  • Enviroment 객체는 옵저버 내에서 초기화 될 수 없어 접근하는 뷰가 화면을 설정하는 동안 구성해야한다.
  • 프로젝트의 SceneDelegate.swift 파일의 willConnectTo 메서드를 수정해야한다.
let contentView = ContentView()
//DemoData 객체의 인스턴트를 저장
let demoData = DemoData()

if let windowScene = scene as? UIWindowScene{
	let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: contentView.environmentObject(demoData))
    self.window = window'
    window.makeKeyAndVisible()
}

//미리보기 뷰에서 environment 객체를 사용하려면 프리뷰 선언뷰를 수정해야한다
struct content_Previews: PreviewProvider{
	static var previews: some View{
    	ContentView().environmentObject(DemoData())
    }
}

🎖 정리

State 프로퍼티

사용자 인터페이스 레이아웃 내의 뷰 상태를 저장
현재 콘텐트 뷰에 관한 것
값은 임시적이어서 해당 뷰가 사라지면 값도 없어진다

Observable 객체 프로퍼티

사용자 인터페이스 밖에 있으며 앱 내의 SwiftUI 뷰 구조체의 하위 뷰에만 필요한 데이터에서 사용
데이터를 표시하는 클래스나 구조체는 ObservableObject 프로토콜을 따라야함
뷰와 바인딩될 프로퍼티는 @Published 프로퍼티 래퍼를 사용하여 선언
뷰 선언부에 Observable 객체 프로퍼티와 바인딩하려면 프로퍼티는 @ObseredObject 프로퍼티 래퍼를 사용

Enviroment 객체 프로퍼티

사용자 인터페이스 밖에 있으며 여러 뷰가 접근 해야하는 데이터에 사용
Observable 객체와 동일한 방법으로 선언
@EnvironmentObject 프로퍼티 래퍼를 사용하여 SwiftUI 뷰 파일 내에 선언
SceneDelegate.swift 파일의 코드를 통해 뷰 화면이 앱에 추가될 때 Enivronment 객체 또한 초기화해야 함
profile
우당탕탕 개발 기록지

0개의 댓글