[SwiftUI] @EnvironmentObject 프로퍼티 래퍼 실습 튜토리얼 예제
Environment 객체
구독(Observable) 객체와 달리 Environment 객체는 뷰에서 뷰로 전달할 필요 없이 모든 뷰가 접근할 수 있다는 것이다.
Environment 객체를 구독해야 하는 객체는 @ObservedObject 래퍼 대신에 @EnvironmentObject 프로퍼티 래퍼를 이용하여 해당 객체를 참조하면 된다.
@EnvironmentObject var demoData: DemoData
[TimerData.swift]
이 클래스는 ObservableObject 프로토콜을 구현하는 것으로 선언되었다.
import Foundation
import Combine
class TimerData : ObservableObject {
@Published var timeCount = 0
var timer : Timer?
init() {
timer = Timer.scheduledTimer(timeInterval: 1.0,
target: self,
selector: #selector(timerDidFire),
userInfo: nil,
repeats: true)
}
@objc func timerDidFire() {
timeCount += 1
}
func resetCount() {
timeCount = 0
}
}
[ContentView .swift] 레이아웃 설계하기
import SwiftUI
struct ContentView: View {
// @ObservedObject var timerData: TimerData = TimerData()
@EnvironmentObject var timerData: TimerData
var body: some View {
NavigationView {
VStack {
Text("Timer count = (timerData.timeCount)")
.font(.largeTitle)
.fontWeight(.bold)
.padding()
Button(action: resetCount) {
Text("Reset Counter")
}
//내비게이션 링크 추가
NavigationLink(destination:
// SecondView(timerData: timerData)) {
SecondView()) {
Text("Next Screen")
}
.padding()
}
}
}
func resetCount() {
timerData.resetCount()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
// ContentView()
ContentView().environmentObject(TimerData())
}
}
[SecondView.swift] 레이아웃 설계하기
import SwiftUI
struct SecondView: View {
// @ObservedObject var timerData: TimerData
@EnvironmentObject var timerData: TimerData
var body: some View {
VStack {
Text("Second View")
.font(.largeTitle)
Text("Timer Count = (timerData.timeCount)")
.font(.headline)
}
.padding()
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView().environmentObject(TimerData())
}
}
교재에는 SceneDelegate.swift 파일을 수정하여 루트(root) 화면이 생성될 때
TimerData 객체가 Environment 객체에 추가되도록 한다고 나와 있지만
최신버전의 Xcode툴에서 SwiftUI 프로젝트 생성시 SceneDelegate.swift파일은 존재하지 않는다.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
let timerData = TimerData()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView:
contentView.environmentObject(timerData))
self.window = window
window.makeKeyAndVisible()
}
}
-알라딘 eBook <핵심만 골라 배우는 SwiftUI 기반의 iOS 프로그래밍> (닐 스미스 지음, 황반석 옮김) 중에서
그래서 @main이 선언되어 있는 swift 파일에 추가해주었더니 정상적으로 동작을 하였다.
근데 이렇게 하는게 맞나?
import SwiftUI
@main
struct ObservableDemoApp: App {
//추가
let timerData = TimerData()
var body: some Scene {
WindowGroup {
//ContentView()
//변경
ContentView().environmentObject(timerData)
}
}
}
[참고 자료]
-알라딘 eBook <핵심만 골라 배우는 SwiftUI 기반의 iOS 프로그래밍> (닐 스미스 지음, 황반석 옮김) 중에서