brunch

매거진 ReactiveX

You can make anything
by writing

C.S.Lewis

by Tilltue Oct 26. 2016

RxSwift, delegate 와 Observable

DelegateProxy, DelegateProxyType

* 이글은 Swift 3.0 , RxSwift 3.0.0 을 기준으로 작성되었습니다.

Swift 에서 일반적인 delegate / protocol 를 사용하는 구조를 생각해보자.

컬러를 선택하는 커스텀 뷰를 만들었다고 가정하자. 

이 뷰는 아래와 같이 선택된 컬러를 전달하는 protocol 을 delegate method 로 사용한다.


- 일반적인 protocol, delegate 메서드 사용방법.


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 형태로 확장해보자.



1. Delegate Proxy 를 만들자.

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

    }

}


2. 원하는 rx_메서드를 delegateProxy 를 통해 연결한다.


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 해주면 된다.


3. 이제 사용하면 된다!


        pickerView?.rx_selectedColor.subscribe(onNext: { color in

            print("onNext")

        }).addDisposableTo(disposeBag)



부록 : 이미 존재하는 RxCocoa delegate 의 확장

- 간단하게 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 함수들을 사용하면 더 활용도가 높을 것으로 생각한다.



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari