SwiftUI

SwiftUI ) @State, @ObservedObject, @EnvironmentObject

Zedd0202 2020. 2. 22. 16:14
반응형

 

안녕하세요 :) Zedd입니다.

오늘은 드디어..."그것"들을 공부해보려고 합니다.

 

State

https://developer.apple.com/documentation/swiftui/state

 

State - SwiftUI | Apple Developer Documentation

Available when Value conforms to ExpressibleByNilLiteral.

developer.apple.com

- SwiftUI는 state로 선언한 모든 프로퍼티의 스토리지를 관리. 

 

- state 값이 변경되면 view가 appearance를 invalidates하고 body를 다시 계산(recomputes)합니다.

 

- 주어진 view에서 state를 single source of truth로 사용 할 것. 

 

- state인스턴스는 value자체가 아님. 값을 읽고 변경하는 수단. state의 기본값에 접근하려면 value 프로퍼티를 사용 할 것.

 

- view의 body에서만 state프로퍼티에 접근 할 것. 따라서 view의 클라이언트에서 state에 접근하지 못하도록 state프로퍼티를 private으로 선언할 것. (state는 특정 view에 속하고, view 외부에서 "절대" 사용되지 않은 간단한 프로퍼티에 적합 -> 해당 상태가 절대로 escape되지 않도록 설계되었다는 것을 강조하기 위해 private으로 표시하는 것이 중요함.)

- @State를 앞에 추가하면 SwiftUI가 자동으로 변경사항을 observe하고 해당 state를 사용하는 view부분을 업데이트.

 

 

 

예를 들어봅시다.

SwiftUI의 segmentedControl.

 

저 selection 파라미터가 binding을 받습니다.

근데 문제는 저기에 constant(0)이 들어가있습니다.

constant라는 이름에서 감이 오듯이 selection이 0(=A)에서 바뀌질 않음.

B나 C를 아무리 탭해도 SegmentedControl이 움직이는 일이 없습니다.....

 

 

현재 selection된 "상태"를 변경하고 해당 state가 저 segmentedControl을 다시 그려야하는데요,

이럴 때 @State로 프로퍼티를 하나 선언하면 됩니다.

 

이렇게요!

 

selection파라미터에 Binding타입이 들어갈 수 있으므로,

특정 state를 selection에 binding할 수 있습니다.

$연산자를 이용해서 바인딩을 얻을 수 있어요.

 

 

 

ObservedObject

https://developer.apple.com/documentation/swiftui/observedobject

 

ObservedObject - SwiftUI | Apple Developer Documentation

Generic Structure ObservedObject Declaration@propertyWrapper @frozen struct ObservedObject where ObjectType : ObservableObject

developer.apple.com

ㅇㅏ니 정의 없는거 뭔데

구글링하겠읍니다...

 

@State같은 경우에는 특정 view에서만 사용하는 프로퍼티였다면 ObservedObject는 

 

- 더 복잡한 프로퍼티(여러 프로퍼티나 메소드가 있거나, 여러 view에서 공유할 수 있는 커스텀 타입이 있는 경우) 대신 @ObservedObject를 사용.

 

- String이나 integer같은 간단한 로컬 프로퍼티대신 외부 참조 타입(external reference type)을 사용한다는 점을 제외하면 @State와 매우 유사.

 

- @ObservedObject와 함께 사용하는 타입은 ObservableObject프로토콜을 따라야함. 

 

- observed object가 데이터가 변경되었음을 view에 알리는 방법은 여러가지가 있지만 가장 쉬운 방법은 @Published 프로퍼티 래퍼를 사용하는 것. = SwiftUI에 view reload를 트리거. 

 

https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-observedobject-to-manage-state-from-external-objects

 

How to use @ObservedObject to manage state from external objects - a free SwiftUI by Example tutorial

Was this page useful? Let us know! 1 2 3 4 5

www.hackingwithswift.com

여기 예제가 제일 간단하고...그런 듯 ㅎㅎ

UserSettings의 score앞에 @Published가 붙었죠?

아까 말했듯이 @Published가 붙었기 때문에 이 score가 변경되면 view를 reload하게 됩니다.

 

+ ) 참고로 왜 UserSetting이 class지? struct면 안되나 싶을 수 있는데 ObservableObject가 class-bound 프로토콜입니다!

 

 

 

EnvironmentObject

https://developer.apple.com/documentation/swiftui/environmentobject

 

EnvironmentObject - SwiftUI | Apple Developer Documentation

Generic Structure EnvironmentObject A dynamic view property that uses a bindable object supplied by an ancestor view to invalidate the current view whenever the bindable object changes. Declaration@frozen @propertyWrapper struct EnvironmentObject where Obj

developer.apple.com

이건 다행히 정의가 있네요.

 

- 바인딩 가능한 객체가 변경될 때 마다 현재 view를 invalidate하기 위해 상위 view(ancestor view)에서 제공한 Binding가능한 객체를 사용하는 dynamic view property.

- 반드시 environmentObject (_ :) 메소드를 호출하여 상위 뷰에서 모델 객체를 설정해야함.

 

 

아니 정의 진짜 개같내

뭐라는거

 

@EnvironmentObject는 

한 문장으로 말할 수 있을 것 같아요

 

"it’s shared data that every view can read if they want to."

 

모든 view가 읽을 수 있는 shared data. 

 

아까 예제를 가지고 한번 해볼게요.

 

아까 만들어놓은 UserSettings이 있었죠. 

아까 정의에서도 말했듯이,

반드시 environmentObject (_ :) 메소드를 호출하여 상위 뷰에서 모델 객체를 설정해야합니다.

 

SceneDelegate의 scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)에 가서

 

"environmentObject (_ :) 메소드를 호출하여 상위 뷰에서 모델 객체를 설정"해줍니다. 

 

그리고 이제 UserSetting을 쓰는 쪽에서

 

@EnvironmentObject를 선언해줍니다. UserSettings타입으로요.

 

저는 아까 딱 거기에서

 

ZeddView로 이동할 수 있게 했어요. ZeddView역시

 

@EnvironmentObject를 선언해줍니다.

 

그럼 

 

제가 ContentViews쪽에서 score를 올리고 ZeddView에 가면 올린 score가 나와야겠죠!?

 

짜잔

 

물론 같은 기능?을 @ObservedObject로도 구현할 수 있지만...

아무튼 지금 중요한건

@EnvironmentObject로 선언하면 앱의 어느곳에서나 공유할 수 있는 데이터가 된다는 것이죠!

모델이 변경되면 이 EnvironmentObject가 바인딩되고 있는 모든곳은

view가 자동으로 업데이트되는게 진짜 좋은 것 같아요

 

 

참고

https://developer.apple.com/documentation/swiftui/state

 

State - SwiftUI | Apple Developer Documentation

Available when Value conforms to ExpressibleByNilLiteral.

developer.apple.com

https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject

 

What’s the difference between @ObservedObject, @State, and @EnvironmentObject? - a free SwiftUI by Example tutorial

Was this page useful? Let us know! 1 2 3 4 5

www.hackingwithswift.com

https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views

 

How to use @EnvironmentObject to share data between views - a free SwiftUI by Example tutorial

Was this page useful? Let us know! 1 2 3 4 5

www.hackingwithswift.com

 

반응형