- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Linux
- rest api
- ReLU
- 명령어
- HTTP
- struct
- 딥러닝
- 시각화
- Optional
- scheduledTimer
- swiftUI
- deeplearning
- rxswift
- Request
- MVC
- 연산자
- SWIFT
- decode
- cocoapods
- Python
- r
- tapply
- ios
- Observable
- substr
- 오블완
- barplot
- 티스토리챌린지
- sigmoid
- SQL
iOS 개발 기록 블로그
Swift ReactorKit @Pulse 사용 목적, 예시, 일반 State와의 차이 본문
https://github.com/ReactorKit/ReactorKit/tree/master/Examples/Counter/Counter
Counter 예제와 같이 봅니다.
ReactorKit에서 @Pulse는 특정 상태 변화를 옵저빙(감지)하기 위해 사용되는 프로퍼티 래퍼입니다. @Pulse를 사용하면 특정 상태 값이 변경될 때만 옵저버가 트리거됩니다. 이는 주로 일회성 이벤트나 특정 상태 변화에 반응하는 경우에 유용합니다.
@Pulse 변수
@Pulse의 사용 목적
- 일회성 이벤트 처리: 일반적인 상태 변화와는 다르게, 사용자에게 한 번만 표시되어야 하는 알림 메시지나 토스트 메시지 같은 이벤트에 적합합니다. 이러한 이벤트는 상태 변화가 있을 때마다 발생하는 것이 아니라, 한 번 발생하고 나면 상태를 초기화하거나 더 이상 감지되지 않도록 해야 합니다.
- 필요한 상태 변화만 반응: @Pulse를 사용하면 해당 상태 값이 변경될 때만 반응합니다. 이는 불필요한 상태 변화 감지를 줄이고 성능을 최적화할 수 있습니다.
코드 예제
struct State {
var value: Int
var isLoading: Bool
@Pulse var alertMessage: String?
}
일반 State와의 차이
일반 상태 변수를 사용하면 상태가 변경될 때마다 모든 구독자가 반응합니다. 예를 들어, alertMessage가 일반 상태 변수라면, 매번 상태가 업데이트될 때마다 UI가 업데이트를 시도할 수 있습니다. 이는 다음과 같은 문제가 발생할 수 있습니다:
- 불필요한 업데이트: 상태가 자주 변경되는 경우, 불필요하게 UI가 업데이트될 수 있습니다.
- 일회성 이벤트 처리의 어려움: alertMessage가 매번 상태가 변경될 때마다 트리거된다면, 한 번 표시된 알림 메시지가 다시 표시될 수 있습니다.
예제 코드 분석
reactor.pulse(\.$alertMessage)
.compactMap { $0 }
.subscribe(onNext: { [weak self] message in
let alertController = UIAlertController(
title: nil,
message: message,
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(
title: "OK",
style: .default,
handler: nil
))
self?.present(alertController, animated: true)
})
.disposed(by: disposeBag)
- reactor.pulse(\\\\.$alertMessage): @Pulse로 정의된 alertMessage가 변경될 때만 트리거됩니다.
- .compactMap { $0 }: alertMessage가 nil이 아닌 경우에만 처리합니다.
- subscribe(onNext:): 알림 메시지를 UI에 표시합니다.
결론
@Pulse를 사용하는 이유는 특정 상태 변화에만 반응하기 위해서입니다. 특히 일회성 이벤트나 특정 조건에만 반응해야 하는 경우에 유용합니다. 일반 상태 변수로 대체할 수 있지만, 그 경우 불필요한 업데이트가 발생할 수 있고, 일회성 이벤트 처리가 어려울 수 있습니다. @Pulse는 이러한 문제를 해결해 주기 때문에 사용이 권장됩니다.
Pulse 사용 예시
@Pulse는 주로 일회성 이벤트나 특정 조건이 충족될 때만 반응해야 하는 상태를 관리하는 데 유용합니다. 아래에 @Pulse를 사용하기 좋은 몇 가지 예시를 소개합니다:
1. 네비게이션 이벤트
앱에서 특정 액션이 발생할 때 다른 화면으로 이동해야 하는 경우에 사용됩니다.
struct State {
@Pulse var navigateToDetail: Bool?
}
// Reactor
if someCondition {
return .just(.setNavigateToDetail(true))
}
// ViewController
reactor.pulse(\.$navigateToDetail)
.compactMap { $0 }
.filter { $0 == true }
.subscribe(onNext: { [weak self] _ in
let detailViewController = DetailViewController()
self?.navigationController?.pushViewController(detailViewController, animated: true)
})
.disposed(by: disposeBag)
2. 애니메이션 트리거
애니메이션이 특정 상태 변화에 의해 한 번만 실행되어야 하는 경우에 사용됩니다.
struct State {
@Pulse var triggerAnimation: Bool?
}
// Reactor
if someCondition {
return .just(.setTriggerAnimation(true))
}
// ViewController
reactor.pulse(\.$triggerAnimation)
.compactMap { $0 }
.filter { $0 == true }
.subscribe(onNext: { [weak self] _ in
self?.runAnimation()
})
.disposed(by: disposeBag)
3. 폼 검증 결과
폼을 제출할 때 검증 결과를 표시하는 메시지에도 사용될 수 있습니다.
struct State {
@Pulse var formValidationResult: String?
}
// Reactor
if isValidForm {
return .just(.setFormValidationResult("Form is valid"))
} else {
return .just(.setFormValidationResult("Form is invalid"))
}
// ViewController
reactor.pulse(\.$formValidationResult)
.compactMap { $0 }
.subscribe(onNext: { [weak self] message in
self?.showValidationResult(message)
})
.disposed(by: disposeBag)
4. 로딩 인디케이터 표시
네트워크 요청이나 긴 작업이 완료되었을 때 로딩 인디케이터를 숨기는 데 사용될 수 있습니다.
struct State {
@Pulse var showLoading: Bool?
}
// Reactor
func mutate(action: Action) -> Observable<Mutation> {
switch action {
case .startLoading:
return Observable.concat([
Observable.just(Mutation.setShowLoading(true)),
someLongRunningTask().map { _ in Mutation.setShowLoading(false) }
])
}
}
// ViewController
reactor.pulse(\.$showLoading)
.compactMap { $0 }
.subscribe(onNext: { [weak self] show in
self?.loadingIndicator.isHidden = !show
})
.disposed(by: disposeBag)
5. 권한 요청
앱에서 특정 권한을 요청하는 경우, 권한 요청이 완료된 후 사용자에게 알림을 표시하는 데 사용할 수 있습니다.
struct State {
@Pulse var permissionRequestResult: Bool?
}
// Reactor
func mutate(action: Action) -> Observable<Mutation> {
switch action {
case .requestPermission:
return requestPermission().map { granted in
return Mutation.setPermissionRequestResult(granted)
}
}
}
// ViewController
reactor.pulse(\.$permissionRequestResult)
.compactMap { $0 }
.subscribe(onNext: { [weak self] granted in
if granted {
self?.showPermissionGrantedMessage()
} else {
self?.showPermissionDeniedMessage()
}
})
.disposed(by: disposeBag)
이러한 다양한 사례에서 @Pulse를 사용하면, 상태 변화가 특정 조건에만 반응하도록 만들 수 있어 불필요한 UI 업데이트를 방지하고, 보다 명확한 상태 관리가 가능합니다.
'iOS' 카테고리의 다른 글
Xcode 16 + iOS 18 UICollectionView 크래시 원인 및 개선 방안: NSInternalInconsistencyException (0) | 2025.01.12 |
---|---|
[Swift] 프로퍼티를 init 메서드에서 초기화, 선언 시 초기화 차이 (1) | 2024.09.11 |
iOS(Swift) 네비게이션 바 아이템 간격 조절 (imageInsets) (0) | 2022.10.10 |
iOS (Swift) CocoaPods 사용하기 4탄 (라이브러리 삭제하는 방법) (0) | 2022.07.19 |
iOS (Swift) CocoaPods 사용하기 3탄 (예시, 사용 프로세스) (0) | 2022.07.17 |