DelegateProxy, DelegateProxyType
* 이글은 Swift 3.0 , RxSwift 3.0.0 을 기준으로 작성되었습니다.
Swift 에서 일반적인 delegate / protocol 를 사용하는 구조를 생각해보자.
컬러를 선택하는 커스텀 뷰를 만들었다고 가정하자.
이 뷰는 아래와 같이 선택된 컬러를 전달하는 protocol 을 delegate method 로 사용한다.
protocol ColorPicker {
func selected(color: UIColor)
}
class ColorPickerView: UIView {
weak var delegate: ColorPicker? = nil
func selected(color: UIColor){
self.delegate?.selected(color: color)
}
}
class ViewController: UIViewController,ColorPicker {
var pickerView: ColorPickerView?
func selected(color: UIColor) {
print("selected color")
}
override func viewDidLoad() {
super.viewDidLoad()
pickerView = ColorPickerView()
pickerView?.delegate = self
}
}
만약 아래와 같은 구문으로 쓴다면 어떨까?
pickerView?.rx_selectedColor.subscribe(onNext: { color in
print("onNext")
}).addDisposableTo(disposeBag)
이렇게 delegate method 를 rx_delegate 형태로 확장해보자.
Rx 의 DelegateProxy 를 상속받고, DelegateProxyType,ColorPicker 프로토콜에 따르도록 아래와 같이 구성한다.
class RxColorPickerDelegateProxy: DelegateProxy,DelegateProxyType,ColorPicker {
internal func selected(color: UIColor) {
}
static func currentDelegateFor(_ object: AnyObject) -> AnyObject? {
let pickerView: ColorPickerView = object as! ColorPickerView
return pickerView.delegate as AnyObject?
}
static func setCurrentDelegate(_ delegate: AnyObject?, toObject object: AnyObject) {
let pickerView: ColorPickerView = object as! ColorPickerView
pickerView.delegate = delegate as? ColorPicker
}
}
extension ColorPickerView {
public var rx_delegate: DelegateProxy {
return RxColorPickerDelegateProxy.proxyForObject(self)
}
public var rx_selectedColor: Observable<UIColor?> {
return rx_delegate.sentMessage(#selector(RxColorPickerDelegateProxy.selected(color:))).map{ a in a[0] as? UIColor }
}
}
* 여기서 a 는 selected 함수 parameter를 의미한다. Observable<[Any]> 로 전달 되므로 필요한 형태로 mapping 해주면 된다.
pickerView?.rx_selectedColor.subscribe(onNext: { color in
print("onNext")
}).addDisposableTo(disposeBag)
- 간단하게 2번 과정을 통해 바로 observable 을 생성하면 된다.
예를 들어 UIScrollViewDelegate 의 scrollViewWillBeginDragging 를 Observable 로 사용하려면
tableView.rx.delegate
.sentMessage(#selector(UIScrollViewDelegate.scrollViewWillBeginDragging(_:)))
.map{ a in a[0] as? UIScrollView }.subscribe(onNext: { scrollView in
}).addDisposableTo(disposeBag)
이렇게 해줘도 되고 위에서 확장한 것과 같이 UITableView 에서 확장해서 rx 메서드로 만들어 두고 써도 된다.
사견: RxSwift 를 프로젝트 전반적으로 사용한다면 이런 다양한 방법을 통해 코드를 일관성 있게 유지할 수 있을 것 같다. 또 이 렇게 delegate 도 Rx 메서드로 만들어 둔다면 다른 Observable 과의 결합이나, Utility 함수들을 사용하면 더 활용도가 높을 것으로 생각한다.