이는 @ObservdeObject
와 똑같은 기능을 한다. 사용하기 좋은 경우는, View 자체가 소유한 객체를 처리시에만 선언하는게 좋다.
값을 실제로 생성하고 소유하는 뷰에서 선언하는편이 좋다. 최상위 View
에서 선언 후, 나머지 뷰에는 @EnvironmentObject
로 선언을 하면, 선언된 값을 공유하므로, 값의 변경이 일어난다면, 해당 값을 공유 하는 모든 View가 업데이트 됩니다. (꽤 유용한듯 보임, 값의 변경으로 뷰가 업데이트 되는 경우는 @Published
로 선언한 경우에 그러한듯 하다)
View 내부에서 코드를 수정하여, 방대함을 방지하는 방법에 대해서 알아보겠습니다.
// 1.이미지의 썸네일을 생성하는 코드
Image(movie.image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
// 2. 수정한 코드
extension Image {
func asThumnail(width: CGFloat = 100) -> some View {
resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: width)
}
}
1번 코드에서는 의도파악이 힘들지만, 2번 코드에서 확장을하고, 함수를 추가 하였기 때문에, 해당 뷰에서 코드를 줄일 수 있고, 의도 파악이 쉬워지고, 수정을 할경우에도 확장한 부분에서 수정하면 된다.
-> 수정자를 의미적으로 의미있게 만드는 작업 !
먼저, 프로퍼티 래퍼에서 @State 가 들어있는 키워드는 값을 실제로 소유하고 있다는 의미이다.
실제 값을 소유하는지 아닌지에 대한 의미이다.
값을 소유하는 래퍼로는
등이 있고
값을 소유하지 않는 래퍼(Property Wrappers that are not sources of truth) 로는
가 존재한다.
View에 새 프로퍼티를 만들고 싶을 떄 잘 모르겠다면, 값 유형에는 @State
를, 참조 유형에는 @StateObject
를 사용한다고 생각하면 좋다.
다른 곳에 생성된 값을 참조하는 경우에는, 값 타입으로는 @Binding
, 참조 타입으로는 @ObservedObject, @EnvrionmentObject
를 사용하면 된다.
실제 데이터는 한 곳에 있어야 한다는 의믜이다. SwiftUI에서 주로 활용해야 할듯
import SwiftUI
@main
struct NC1App: App {
@StateObject private var modelData = ModelData()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(modelData)
}
}
}
위 코드 처럼, 최상위 부모 View에서 데이터를 인스턴스화 하고, 자식 뷰에 환경 개체로 추가 하면, 전체 앱에서 모든 dataModel의 모든 속성에서 접근이 가능하다.
그리고 위 환경 개체를 사용하여서, 로그인 화면을 조건문을 통해 보여줄 수 있다.
if dataModel.isLoggedIn {
ContentView()
} else {
LoginView()
}
// 뒤의 .environmentObject(modelData)를 붙여 줘야 오류가 발생하지 않음
이런 방식의 작성이, 앱의 UI가 작동할 수 있는 모든 다양한 방식을 훨씬 더 쉽게 이해 하게끔 해줍니다.
용어 설명
SwiftUI에서 '환경' 이라는 것은, View와 그 자식 간에 공유되는 변수와 객체의 저장소이다.
오홍홍