티스토리 뷰
RxCocoa traits
RxSwift 문서를 정리 및 요약해보겠습니다. (출처 - RxCocoa Traits)
ControlProperty 와 ControlEvent 는 UI 요소의 속성을 나타내는 Observable/ObservableType 의 trait 입니다.
👉 ControlProperty
ControlProperty 는 ObservableType 과 ObserverType 을 동시에 채택하는 ControlPropetyType 을 채택합니다.
Subject 와 같이 프로퍼티에 새로운 값을 관찰할 수도 방출할 수도 있습니다.
public struct ControlProperty<PropertyType> : ControlPropertyType {
    ...
}
/// Protocol that enables extension of `ControlProperty`.
public protocol ControlPropertyType : ObservableType, ObserverType {
    /// - returns: `ControlProperty` interface
    func asControlProperty() -> ControlProperty<Element>
}
예를 들어, UITextField+Rx.Swift 에서는 다음과 같이 text 를 ControlProperty 로 가집니다.
extension Reactive where Base: UITextField { ...
    public var text: ControlProperty<String?> {
        return value
    }
...
}
Observable 채택한 text 에 대한 변경사항을 관찰하기 위해서 subscribe 를 수행할 수 있습니다.
ObserverType 채택하였기 때문에 다음과 같이 사용할 수 있습니다.
drive(_:) 와 bind(to:) 는 ObserverType 을 채택한 객체를 파라미터로 전달할 수 있습니다.
.drive(textfield.rx.text)
.bind(to: textfield.rx.text)
위의 예시처럼 ControlProperty 는 시퀀스가 오직 초기 control value 와 사용자가 시작한 값 변경만을 나타냅니다.
속성은 다음과 같습니다.
- never fails
 - never errors out
- UI 작업에 특화되있는 RxCocoa 의 Trait 이기 때문에 스트림이 끊기지 않도록 실패를 하지 않도록 합니다.
 
 share(replay: 1)behavior- 구독 시에 마지막 요소가 있는 경우 즉시 replay 됩니다.
 
- 할당 해제될때 
Complete방출됩니다. MainScheduler.instance에 이벤트를 전달합니다.ControlEvent의 구현은 이벤트 시퀀스가 main scheduler(subscribeOn(ConcurrentMainScheduler.instance)동작)에서 구독되도록 합니다.
좀 더 예시 코드를 살펴보겠습니다. UISearchBar+Rx.swift 에서는 text 를
 extension Reactive where Base: UISearchBar {
    /// Reactive wrapper for `text` property.
    public var value: ControlProperty<String?> {
        let source: Observable<String?> = Observable.deferred { [weak searchBar = self.base as UISearchBar] () -> Observable<String?> in
            let text = searchBar?.text
            return (searchBar?.rx.delegate.methodInvoked(#selector(UISearchBarDelegate.searchBar(_:textDidChange:))) ?? Observable.empty())
                    .map { a in
                        return a[1] as? String
                    }
                    .startWith(text)
        }
        let bindingObserver = Binder(self.base) { (searchBar, text: String?) in
            searchBar.text = text
        }
        return ControlProperty(values: source, valueSink: bindingObserver)
    }
}
UISegmentedControl 에서는 selectedSegmentIndex 를 래핑하고 있습니다.
extension Reactive where Base: UISegmentedControl {
    /// Reactive wrapper for `selectedSegmentIndex` property.
    public var selectedSegmentIndex: ControlProperty<Int> {
        value
    }
    /// Reactive wrapper for `selectedSegmentIndex` property.
    public var value: ControlProperty<Int> {
        return UIControl.rx.value(
            self.base,
            getter: { segmentedControl in
                segmentedControl.selectedSegmentIndex
            }, setter: { segmentedControl, value in
                segmentedControl.selectedSegmentIndex = value
            }
        )
    }
}
👉 ControlEvent
ControlEvent 는 ObservableType 을 채택하는 ControlEventType 을 채택합니다.
public struct ControlEvent<PropertyType> : ControlEventType {
    ...
}
/// A protocol that extends `ControlEvent`.
public protocol ControlEventType : ObservableType {
    /// - returns: `ControlEvent` interface
    func asControlEvent() -> ControlEvent<Element>
}
속성은 다음과 같습니다.
- never fails
 - never errors out
- UI 작업에 특화되있는 RxCocoa 의 Trait 이기 때문에 스트림이 끊기지 않도록 실패를 하지 않도록 합니다.
 
 - 구독 시 초기 값을 보내지 않습니다.
 - 할당 해제될때 
Complete방출됩니다. MainScheduler.instance에 이벤트를 전달합니다.ControlEvent의 구현은 이벤트 시퀀스가 main scheduler(subscribeOn(ConcurrentMainScheduler.instance)동작)에서 구독되도록 합니다.
예를 들어, UIButton+Rx.Swift 
extension Reactive where Base: UIButton {
    /// Reactive wrapper for `TouchUpInside` control event.
    public var tap: ControlEvent<Void> {
        controlEvent(.touchUpInside)
    }
}
UICollectionView+Rx.swift 에서도 확인할 수 있습니다.
extension Reactive where Base: UICollectionView {
    /// Reactive wrapper for `delegate` message `collectionView:didSelectItemAtIndexPath:`.
    public var itemSelected: ControlEvent<IndexPath> {
        let source = delegate.methodInvoked(#selector(UICollectionViewDelegate.collectionView(_:didSelectItemAt:)))
            .map { a in
                return a[1] as! IndexPath
            }
        return ControlEvent(events: source)
    }
}
tap, itemSelected 의 변경사항을 관찰하기 위해서 subscribe 을 사용할 수 있습니다.
출처 :
https://github.com/ReactiveX/RxSwift/blob/main/Documentation/Traits.md
'iOS > RxSwift' 카테고리의 다른 글
| iOS) MVVM + RxSwift, RxCocoa 적용 (0) | 2023.08.31 | 
|---|---|
| RxSwift) withUnretained 와 이를 대체하는 subscribe(with:onNext:…) (0) | 2023.07.05 | 
| RxSwift) Traits(1) - Driver, Signal (0) | 2023.02.27 | 
| RxSwift) error handling - catch, catchAndReturn, retry, retry(when:), materialize, dematerialize (0) | 2023.02.17 | 
| RxSwift) 6.Subjects (0) | 2022.07.14 | 
- YPImagePicker
 - OpenSourceLibrary
 - APNS
 - Notification
 - RxCocoa
 - rxswift
 - WidgetKit
 - github
 - 2022 KAKAO TECH INTERNSHIP
 - Objective-C
 - MVVM
 - WWDC
 - 서버통신
 - SwiftUI
 - MOYA
 - IOS
 - watchOS
 - UserDefaults
 - urlsession
 - containerBackground
 - Widget
 - CloneCoding
 - Protocol
 - Firebase
 - projectsetting
 - Swift
 - WWDC22
 - Algorithm
 - async/await
 - configurable widget
 
| 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 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 | 
- Total
 
- Today
 
- Yesterday