본문 바로가기
Swift

[SwiftUI 스터디] Swift 5.9 Observation

by thekoon 2023. 10. 8.

며칠전에 어느때와 다름없이

앱스쿨 저녁반에서 놀고있는데

튜나센세가 SwiftUI로 간단한 앱을 만들고 계시더라구요

신나게 구경하고 있는데 이번에 새로 나온 Observation을 사용하시는거에요!

굉장히 간단하고 편해보이더라구요

그래서 이번엔 Observation에 대해 공부해보았습니다!

 

https://developer.apple.com/documentation/observation

 

Observation | Apple Developer Documentation

Make responsive apps that update the presentation when underlying data changes.

developer.apple.com

기존의 ObservableObject를 marco를 통해 @Obserbable로 활용하는 것 같았는데

제가 아직 macro도 자세히 공부하지 못하고 구경만 한 수준이라 추후에 macro에 대해 더 공부해봐야겠습니다!

 

https://developer.apple.com/videos/play/wwdc2023/10149/

 

Discover Observation in SwiftUI - WWDC23 - Videos - Apple Developer

Simplify your SwiftUI data models with Observation. We'll share how the Observable macro can help you simplify models and improve your...

developer.apple.com

아래의 예시는 WWDC를 보고 정리한 내용입니다.

 

기존의 ObservableObject는

class FoodTruckModel: ObservableObject {
    @Published var orders: [Order] = []
    @Published var donuts = Donut.all
}

이렇게 선언했다면, 이제는 

 

@Observable
class FoodTruckModel {    
    var orders: [Order] = []
    var donuts = Donut.all
}

이렇게 @Observable 선언만 해주면

ObservableObject 프로토콜 선언할 필요도 없고, @Published 프로퍼티 래퍼도 필요없습니다.

 

 

뷰에서 사용할때로

기존의 @ObservedObject방식이 아닌

struct DonutMenu: View {
  @ObservedObject let model: FoodTruckModel
} 

 

일반 변수처럼

let model: FoodTruckModel 이렇게 선언하고, 접근해서 사용할 수 있습니다!

정말 간단하고 편해졌네요!!

struct DonutMenu: View {
  let model: FoodTruckModel
    
  var body: some View {
    List {
      Section("Donuts") {
        ForEach(model.donuts) { donut in
          Text(donut.name)
        }
        Button("Add new donut") {
          model.addDonut()
        }
      }
    }
  }
}

 

 

활용하는 SwiftUI 세 가지 프로퍼티 래퍼

@State: 뷰가 모델에 자체 상태를 저장해야하는 경우

여기서 donutToAdd 프로퍼티는 DonutListView의 라이프사이클에 따라 관리됨

struct DonutListView: View {
    var donutList: DonutList
    @State private var donutToAdd: Donut?

    var body: some View {
        List(donutList.donuts) { DonutView(donut: $0) }
        Button("Add Donut") { donutToAdd = Donut() }
            .sheet(item: $donutToAdd) {
                TextField("Name", text: $donutToAdd.name)
                Button("Save") {
                    donutList.donuts.append(donutToAdd)
                    donutToAdd = nil
                }
                Button("Cancel") { donutToAdd = nil }
            }
    }
}

 

@Environment: 전역적으로 접근 가능

@Observable class Account {
  var userName: String?
}

struct FoodTruckMenuView : View {
  @Environment(Account.self) var account

  var body: some View {
    if let name = account.userName {
      HStack { Text(name); Button("Log out") { account.logOut() } }
    } else {
      Button("Login") { account.showLogin() }
    }
  }
}

 

@Bindable: 새로 나옴. 가벼움. 그냥 바인딩만 가볍게 할 경우 사용

@Observable class Donut {
  var name: String
}

struct DonutView: View {
  @Bindable var donut: Donut

  var body: some View {
    TextField("Name", text: $donut.name)
  }
}

 

WWDC에서는 각 상황에 맞게 사용하라고 하는데 아직 잘 와닿지가 않아서 자주 적용해보면서 익혀야 할 것 같습니다!

 

아직 iOS17 지원 앱이 많지가 않아서 당분간은 기존의 옵저버블 방식을 사용해야될 것 같지만

새로운 기능들을 연습해보면서 적용해보려 합니다! 화이팅!!