Is this the best way to convert Swift protocol to

2019-06-07 05:10发布

问题:

Sorry I could not come up with better title than that, Ill modify it if anybody suggests a better one after.

I have a protocol

@objc public protocol MyCollectionViewProtocol {
    func scrollViewShouldScrollToTop()
}

I have declared it to be @objc because unfortunately DelegateProxy does not work with non NSObject protocols (I assume, if somebody can clarify that, will be a great help)

My collectionView

public class MyCollectionView: UICollectionView {
  weak var cvDelegate : MyCollectionViewProtocol?
  ... //rest of the code isnt related to this question in particular 

Now I declare delegate proxy as

open class RxMyCollectionViewDelegateProxy : DelegateProxy<MyCollectionView, MyCollectionViewProtocol>
    , DelegateProxyType
, MyCollectionViewProtocol {

    public static func currentDelegate(for object: MyCollectionView) -> MyCollectionViewProtocol? {
        return object.cvDelegate
    }

    public static func setCurrentDelegate(_ delegate: MyCollectionViewProtocol?, to object: MyCollectionView) {
        object.cvDelegate = delegate
    }


    public weak private(set) var collectionView: MyCollectionView?


    internal lazy var shouldScrollPublishSubject: PublishSubject<Void> = {
        let localSubject = PublishSubject<Void>()
        return localSubject
    }()

    public init(collectionView: ParentObject) {
        self.collectionView = collectionView
        super.init(parentObject: collectionView, delegateProxy: RxMyCollectionViewDelegateProxy.self)
    }

    // Register known implementations
    public static func registerKnownImplementations() {
        self.register { RxMyCollectionViewDelegateProxy(collectionView: $0) }
    }


    //implementation of MyCollectionViewProtocol
    public func scrollViewShouldScrollToTop() {
        shouldScrollPublishSubject.onNext(())
        self._forwardToDelegate?.scrollViewShouldScrollToTop()
    }

    deinit {
        shouldScrollPublishSubject.onCompleted()
    }
}

Finally I declare my Reactive extension for MyCollectionView as

extension Reactive where Base: MyCollectionView {
    public var delegate: DelegateProxy<MyCollectionView, MyCollectionViewProtocol> {
        return RxMyCollectionViewDelegateProxy.proxy(for: base)
    }

    public var shouldScrollToTop: ControlEvent<Void> {
        let source = RxMyCollectionViewDelegateProxy.proxy(for: base).shouldScrollPublishSubject
        return ControlEvent(events: source)
    }
}

Finally, I use it as

    collectionView.rx.shouldScrollToTop.debug().subscribe(onNext: { (state) in
        print("I should scroll to top")
    }, onError: { (error) in
        print("errored out")
    }, onCompleted: {
        print("completed")
    }, onDisposed: {
        print("Disposed")
    }).disposed(by: disposeBag)

Question

  1. Because none of the online tutorials(Raywenderlich)/courses (Udemy)/Books(Raywenderlich) explains how to convert the swift protocol to Rx style am confused as what I am doing is correct or wrong. The code works but even the worst designed code might work, hence I wanna be sure what am doing is correct or am messing something. I wrote the above code following the approach used in UIScrollView+Rx.swift and RxScrollViewDelegateProxy.swift

  2. Though the code above works only for protocols without any return type example method I used above func scrollViewShouldScrollToTop() has no return type associated with it. I could not imagine how could I use the DelegateProxy above to convert the protocol methods with return types, like numberOfRowsInSection which has Int as return type.

I happened to look at the RxDataSource implementation and realized in order to convert cellForRowAtIndexPath RxDataSource constructor expects you to pass the block as a init parameter and executes it whenever tableView calls cellForRowAtIndexPath in its proxyDelegate.

Now I could do the same thing if thats the only way out. Need to know is that how am supposed to code it or can I modify ProxyDelegate implementation above to convert the protocol method with return types.