Link
Notice
HIT해
[iOS/TCA] ifLet 본문
728x90
ifLet 어디서 많이 보지 않았는가
바로 if let 이랑 비슷한 역할을 한다.
주로 상태가 존재하는 경우에만 특정 뷰의 Modifier를 적용하려고 할때 사용된다.
상태의 값이 존재할때만 활성화되고 그렇지 않다면 무시된다.
예시 코드를 보자
1. Reducer
@Reducer
struct AlertAndConfirmationDialog {
@ObservableState
struct State: Equatable {
@Presents var alert: AlertState<Action.Alert>?
@Presents var confirmationDialog: ConfirmationDialogState<Action.ConfirmationDialog>?
var count = 0
}
enum Action {
case alert(PresentationAction<Alert>)
case alertButtonTapped
case confirmationDialog(PresentationAction<ConfirmationDialog>)
case confirmationDialogButtonTapped
@CasePathable
enum Alert {
case incrementButtonTapped
}
@CasePathable
enum ConfirmationDialog {
case incrementButtonTapped
case decrementButtonTapped
}
}
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .alert(.presented(.incrementButtonTapped)),
.confirmationDialog(.presented(.incrementButtonTapped)):
state.alert = AlertState { TextState("Incremented!") }
state.count += 1
return .none
case .alert:
return .none
// Alert
case .alertButtonTapped:
state.alert = AlertState {
TextState("Alert!")
} actions: {
ButtonState(role: .cancel) {
TextState("Cancel")
}
ButtonState(action: .incrementButtonTapped) {
TextState("Increment")
}
} message: {
TextState("This is an alert")
}
return .none
// 줄어들었다는 Alert 출력
case .confirmationDialog(.presented(.decrementButtonTapped)):
state.alert = AlertState { TextState("Decremented!") }
state.count -= 1
return .none
case .confirmationDialog:
return .none
// Dialog 표시
case .confirmationDialogButtonTapped:
state.confirmationDialog = ConfirmationDialogState {
TextState("Confirmation dialog")
} actions: {
ButtonState(role: .cancel) {
TextState("Cancel")
}
// 증가 경고문 출력
ButtonState(action: .incrementButtonTapped) {
TextState("Increment")
}
// 감소 경고문 출력
ButtonState(action: .decrementButtonTapped) {
TextState("Decrement")
}
} message: {
TextState("This is a confirmation dialog.")
}
return .none
}
}
.ifLet(\.$alert, action: \.alert)
.ifLet(\.$confirmationDialog, action: \.confirmationDialog)
}
}
.ifLet(\.$alert, action: \.alert)
.ifLet(\.$confirmationDialog, action: \.confirmationDialog)
사용하려는 뷰의 프로퍼티로 해당 값이 없다면 사용을 못하게 하는 것이다.
왜냐하면 해당 기능들은 뷰에 alert와 showDialog 가 없다면 사용할 수 없는 리듀서 일테니 이런 프로퍼티를 가지고 있을때만 리듀서의 해당 state Action을 사용하겠다고 말하는 것이다.
AlertView
struct AlertAndConfirmationDialogView: View {
@Bindable var store: StoreOf<AlertAndConfirmationDialog>
var body: some View {
Form {
Section {
AboutView(readMe: readMe)
}
Text("Count: \(store.count)")
Button("Alert") { store.send(.alertButtonTapped) }
Button("Confirmation Dialog") { store.send(.confirmationDialogButtonTapped) }
}
.navigationTitle("Alerts & Dialogs")
.alert($store.scope(state: \.alert, action: \.alert))
.confirmationDialog($store.scope(state: \.confirmationDialog, action: \.confirmationDialog))
}
}
만약 두 프로퍼티를 지우게 된다면 리듀서의 어떤 상태변화도 일어나지 않는다.
오류 방지를 위한 프로퍼티라고 생각하면 좋다.
그런데 아쉬운점은 두 ifLet 중 하나만 주석처리를 할 경우 주석처리 되지 않은 Reducer의 액션들은 실행된다.
'Swift > CS' 카테고리의 다른 글
[iOS/SwiftUI] refreshable (0) | 2024.08.31 |
---|---|
[iOS/SwiftUI] NavigationStack 공식문서 뜯어보기 (0) | 2024.08.31 |
[iOS/SwiftUI] TCA finish() 알아보기 (0) | 2024.08.30 |
[iOS/SwiftUI] defer (0) | 2024.08.30 |
[iOS/TCA] TwoCounters로 TCA Scope알아보기 (0) | 2024.08.30 |