반응형

 

Hacking with Swift 사이트의 강좌 번역본입니다.

 

[원문 : https://www.hackingwithswift.com/quick-start/swiftui/adding-items-to-an-order-with-environmentobject]

 

Adding items to an order with @EnvironmentObject

[동영상 강좌 : https://youtu.be/YfNhwMhYtnI]

자, 우리가 실제로(actually) 무엇을 했나요?

 

흠, 우리는 사용자가 메뉴에 있는 항목을 보고 주문에 추가하길 원했습니다. 또한, 우리는 이렇게 주문한 항목들이 앱의 다른곳에 표시되길 원합니다.

 

Environment objects는 SwiftUI의 여러 곳에서 데이터 공유하는 방법이지만, 그것들은 UI가 로딩됨에 따라 다른 것을 쉽게 보여 줄 수 있기 때문에, 완전한 해결책은 아닙니다. ObservableObject 프로토콜을 사용해서 Order 클래스에 변경사항을 알리는 기능을 제공했었고, SwiftUI가 해당 알림을 감시하고 UI를 다시 로드하도록 할 수 있습니다. 

 

방금 Order의 인스턴스를 만들었고 environment 안에 배치했습니다. 결과적으로, ContentView에서 온 모든 뷰는 주문을 다시 읽을 수 있고 어떻게든 조작할 수 있습니다. 

 

상세 화면에 있는 주문에 항목들을 추가하길 원하며, ItemDetail.swift로 돌아가서 다음과 같은 프로퍼티를 지정하세요.

@EnvironmentObject var order: Order

 

기본 값을 제공하지 않았으므로, Swift의 엄격한 초기화 규칙에 문제가 있을 것이라 생각할지도 모릅니다. 하지만, @EnvironmentObject 프로퍼티 래퍼는 약간의 마법을 부립니다: 우리가 이미 environment에서 값을 설정했기 때문에, 해당 변수가 코드에서 값을 가지지 않도록 합니다.

 

해당 뷰가 보여질때, SwiftUI는 자동으로 environment objects의 목록에서 Order 타입을 찾아서, 해당 프로퍼티에 첨부합니다. Order 객체를 찾을수 없는 경우에는 문제가 될수 있습니다: 우리가 말했던 것 처럼 가끔씩 찾을수 없고 코드는 크래쉬 날것입니다. 이것은 마치 암묵적으로 언래핑된 옵셔널(unwrapped optional)같기에, 주의해야 합니다.

 

Swift에서 @EnvironmentObject는 마치 @Published 처럼, 또 다른 프로퍼티 래퍼(property wrapper)입니다. 우리가 방금 전에 언급했던 자동으로 첨부하는 기능을 얻는 것을 의미하지만,SwiftUI가 변경에 대해 객체를 관찰하고 변경 알림이 있을때 UI를 갱신하는 것을 말합니다.

 

ItemDetail에 있는 주문을 관리하기 위해 약간의 코드를 추가하기 전에, 또 다른 미리보기 문제를 고쳐야 합니다. 알다시피, ItemDetail이 나타날때, Order 타입의 객체가 environment에 있을 것이라 약속하고, 만들어서, SceneDelegate.swift에서 전달합니다. 앱이 실제로 실행할때 좋은 작업이지만, Xcode 미리보기에서는 scene delegate로 부터 실행되지 않습니다 - 우리는 뷰 파일 끝부분에 PreviewProvider코드로 만들었습니다.

 

해당 미리보기 코드는 디버그 모드일때만 빌드될 것입니다 - Xcode에서 빌드할때는 App Store와는 반대입니다. 이것은 미리보기에 관련된 코드를 넣는 것이 안전하다는 것이며, 이 경우에 모두 제대로 동작하는 임시 Order 인스턴스가 될 것입니다. 

struct ItemDetail_Previews: PreviewProvider {
    static let order = Order()

    static var previews: some View {
        NavigationView {
            ItemDetail(item: MenuItem.example).environmentObject(order)
        }
    }
}

 

scene delegate와 동일한 설정을 복제해서, 미리보기가 다시 동작해야 합니다.

 

이제 그 작업은 실제 정책에도 적용할 수 있습니다: 현재 메뉴 항목을 주문에 추가하는 버튼을 추가하세요. SwiftUI에서 버튼은 2가지가 있습니다: 제목 문자열과 버튼을 탭했을때 실행하는 코드를 포함하는 동작 클로져.

Order클래스는 메뉴 항목을 가져오는 이미 add()메소드를 가지고 있으므로, 그것을 동작으로 사용할 것입니다. 제목에서 처럼, 단지 Order this라고 말하는 텍스트를 추가할 것입니다 - 원하는 스타일을 추가할 수 있습니다!

 

ItemDetail의 본문(body)에 spacer 바로앞에 다음을 넣으세요.

Button("Order This") {
    self.order.add(item: self.item)
}.font(.headline)

 

공유된 주문(order)에 추가하는게 전부이지만, 실제로는 아무것도 볼수 없습니다.

 

사용자의 주문을 보여주는 새로운 화면을 만들어야 하며, 기존 컨텐츠 뷰에 탭바를 넣어야 합니다.

 

새로운 SwiftUI View를 만들기 위해 Cmd+N을 누르고, OrderView를 입력합니다. 앱의 남은부분과 동일한 Order 인스턴스가 필요하기 때문에, ItemDetail과 동일한 프로퍼티를 제공해야 합니다.

@EnvironmentObject var order: Order

 

미리보기에서 코드가 비슷한 만큼 제대로 동작하는지도 확인하세요.

struct OrderView_Previews: PreviewProvider {
    static let order = Order()

    static var previews: some View {
        OrderView().environmentObject(order)
    }
}

 

OrderView의 본문에서 처럼, 여기있는 것 모두 이미 알고 있는 것들입니다.

  • List 뷰는 스크롤 가능한 테이블을 제공합니다.

  • 정보를 분할하기 위해 Section 블럭을 사용합니다.

  • ForEach HStack은 주문 항목 배열을 보여주며, 각 항목의 이름과 가격 모두를 보여줍니다.

  • 마지막 두번째 Section은 주문을 위해 이동하는 네비게이션 링크를 보여줍니다.

  • 네비게이션 바 제목은 Order입니다.

  • 테이블(table)에 Grouped 스타일을 적용합니다.

모든 것을 종합해보면 OrderView 구조체를 얻을 수 있습니다.

struct OrderView : View {
    @EnvironmentObject var order: Order

    var body: some View {
        NavigationView {
            List {
                Section {
                    ForEach(order.items) { item in
                        HStack {
                            Text(item.name)
                            Spacer()
                            Text("$\(item.price)")
                        }
                    }
                }

                Section {
                    NavigationLink(destination: Text("Check out")) {
                        Text("Place Order")
                    }
                }
            }
            .navigationBarTitle("Order")
            .listStyle(GroupedListStyle())
        }
    }
}

 

잠시 후에 다시 말하겠지만, 먼저 사용자 인터페이스를 사용할 수 있도록 만들어서 동작을 확인해야 합니다.

 

반응형
Posted by 까칠코더
,