[iOS][Weekly] 2021/11/19

2 분 소요

2021.12.02

[iOS][Weekly] 2021/11/19

본문

내용

⭐️ NEWS ⭐️

1. Swift 빌드가 더 빨라졌다

⭐️ CODE ⭐️

1. (오픈소스) SwiftUI-Navigation에 대해 알아보자

기존 Navigation 뷰의 문제점

  • 현재 SwiftUI에서 지원하는 내비게이션 형태의 뷰 (alert, sheet, navigation links 등)에는 몇가지 문제점이 있다.
  • SwiftUI에서 시트창을 열고 싶으면 아래처럼 열어야 한다.
struct ContentView: View {
  @State var draft: Post?

  var body: some View {
    Button("Edit") {
      self.draft = Post()
    }
    .sheet(item: self.$draft) { (draft: Post) in
      EditPostView(post: draft)
    }
  }
}
  • draft라는 optional value가 있고, draft가 non-nil 일 경우 sheet 뷰를 출력한다.
  • 하지만, 이때 치명적인 단점이 있는데 그것은 sheet 뷰가 열릴 때 클로저로 전달되는 draft가 바인딩 타입이 아니다.
  • 즉, EditPostView에서 draft를 수정해도 기존 뷰(ContentView)의 draft에는 영향이 가지 않는다. -> 즉, 화면 업데이트가 되지 않는다.
  • 또 다른 문제를 보자.
.sheet(item: self.$draft) { (draft: Post) in
  EditPostView(post: draft)
}
.sheet(item: self.$settings) { (settings: Settings) in
  SettingsView(settings: settings)
}
.sheet(item: self.$userProfile) { (userProfile: Profile) in
  UserProfile(profile: userProfile)
}
  • draft가 non-nil 일 경우 EditPostView를, settings가 non-nil일 경우 SettingsView를, userProfile이 non-nil일 경우 UserProfile을 출력하고 싶을 때 이렇게 작성할 수 있겠지만 이를 관리하기는 쉽지 않다.
  • 3개의 optional value가 있기 때문에 가능한 상황은 총 8가지(2^3) 이고, 그중 4가지는 문제가 있다.
draft settings userProfile 예상 동작
nil nil nil 아무 동작 안함
non-nil nil nil EditPostView 출력
nil non-nil nil SettingsView 출력
nil nil non-nil UserProfile 출력
non-nil non-nil nil EditPostView 출력 &SettingsView 출력
non-nil nil non-nil EditPostView 출력 &UserProfile 출력
nil non-nil non-nil SettingsView 출력 &UserProfile 출력
non-nil non-nil non-nil EditPostView 출력 &SettingsView 출력 &UserProfile 출력
  • 4가지 상황이 발생하지 않도록 사용자는 상당한 주의가 필요하게 된다.
  • 요런 여러가지 불편사항들을 개선하기 위해 Swift-Navigation 오픈소스를 만들었다고 한다. 한번 알아보자.

Swift-Navigation 알아보기

  • 오픈소스
  • 위에서 살펴본 여러가지 상태를 컨트롤해야 하는 상황을 위해서 enum을 활용해준다.
  • enum 변수를 바인딩 형태로 넘겨주고 또한 클로저로 enum 파라미터의 바인딩 타입이 오는 것을 눈여겨 보자.
enum Route {
  case draft(Post)
  case settings(Settings)
  case userProfile(Profile)
}

...

@State var route: Route?

...

.sheet(unwrapping: self.$route, case: /Route.draft) { $draft in
  EditPostView(post: $draft)
}
.sheet(unwrapping: self.$route, case: /Route.settings) { $settings in
  SettingsView(settings: $settings)
}
.sheet(unwrapping: self.$route, case: /Route.userProfile) { $userProfile in
  UserProfile(profile: $userProfile)
}
  • Switch, IfCaseLet, CaseLet, IfLet 등 API도 있다.
  • 상태에 따라 출력해야할 뷰가 다를 경우 SwitchCaseLet API를 사용해서 바인딩 타입을 전달받아서 적절하게 처리도 가능하다.
enum ItemStatus {
  case inStock(quantity: Int)
  case outOfStock(isOnBackorder: Bool)
}

struct InventoryItemView {
  @State var status: ItemStatus?

  var body: some View {
    Switch(self.$status) {
      CaseLet(/ItemStatus.inStock) { $quantity in   // <- enum 파라미터가 binding 형태로 내려온다.
        HStack {
          Text("Quantity: \(quantity)")
          Stepper("Quantity", value: $quantity)
        }
        Button("Out of stock") { self.status = .outOfStock(isOnBackorder: false) }
      }

      CaseLet(/ItemStatus.outOfStock) { $isOnBackorder in
        Toggle("Is on back order?", isOn: $isOnBackorder)
        Button("In stock") { self.status = .inStock(quantity: 1) }
      }
    }
  }
}

참고

카테고리: ,

업데이트:

댓글남기기