Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert Delegate to Observable RxSwift?

I have delegate methods, which I need to wrap by Delegate Proxy in RxSwift. I have done it using Bond and Reactive, but here, in RxSwift, I am not able to find the proper way to convert it.

Follow is Protocols

    import UIKit

/**
 A protocol for the delegate of a `DetailInputTextField`.
 */

    @objc
    public protocol CardInfoTextFieldDelegate {

        /**
         Called whenever valid information was entered into `textField`.

         - parameter textField:         The text field whose information was updated and is valid.
         - parameter didEnterValidInfo: The valid information that was entered into `textField`.
         */
        func textField(_ textField: UITextField, didEnterValidInfo: String)

        /**
         Called whenever partially valid information was entered into `textField`.

         - parameter textField:                  The text field whose information was updated and is partially valid.
         - parameter didEnterPartiallyValidInfo: The partially valid information that was entered.
         */
        func textField(_ textField: UITextField, didEnterPartiallyValidInfo: String)

        /**
         Called whenever more text was entered into `textField` than necessary. This can be used to provide this overflow as text in the next text field in the responder chain.

         - parameter textField:      The text field which received more information than required.
         - parameter overFlowDigits: The overflow of text which does not fit into `textField` and might be entered into the next receiver in the responder chain.
         */
        func textField(_ textField: UITextField, didEnterOverflowInfo overFlowDigits: String)
    }

What I did earlier is

import Foundation
import Bond
import Caishen


extension DetailInputTextField {
    var bnd_cardInfoDelegate: ProtocolProxy {
        return protocolProxy(for: CardInfoTextFieldDelegate.self, setter: NSSelectorFromString("setCardInfoTextFieldDelegate:"))
    }

    var bnd_didEnterValidInfo: StreamSignal<NSString> {
        return bnd_cardInfoDelegate.signal(for: #selector(CardInfoTextFieldDelegate.textField(_:didEnterValidInfo:)))
        { (s: PublishSignal<NSString>, _: UITextField, info: NSString) in
            s.next(info)
        }
    }

    var bnd_didEnterPartiallyValidInfo: StreamSignal<NSString> {
        return bnd_cardInfoDelegate.signal(for: #selector(CardInfoTextFieldDelegate.textField(_:didEnterPartiallyValidInfo:)))
        { (s: PublishSignal<NSString>, _: UITextField, info: NSString) in
            s.next(info)
        }
    }

    var bnd_didEnterOverflowInfo: StreamSignal<NSString> {
        return bnd_cardInfoDelegate.signal(for: #selector(CardInfoTextFieldDelegate.textField(_:didEnterOverflowInfo:)))
        { (s: PublishSignal<NSString>, _: UITextField, info: NSString) in
            s.next(info)
        }
    }
}

How can I do same exercise in RxSwift. I tried DelegateProxy but its unclear how it properly wrap it.

like image 690
Sam Shaikh Avatar asked Aug 13 '18 06:08

Sam Shaikh


1 Answers

Due to the popularity of this answer, I have written an article about it: Convert a Swift Delegate to RxSwift Observables

I believe this is the official way of converting a delegate into RxObservables:

class CardInfoTextField: NSObject {
    weak var delegate: CardInfoTextFieldDelegate? = nil
}

@objc
protocol CardInfoTextFieldDelegate {
    @objc optional func textField(_ textField: CardInfoTextField, didEnterValidInfo: String)
    @objc optional func textField(_ textField: CardInfoTextField, didEnterPartiallyValidInfo: String)
    @objc optional func textField(_ textField: CardInfoTextField, didEnterOverflowInfo overFlowDigits: String)
}

extension CardInfoTextField: HasDelegate {
    public typealias Delegate = CardInfoTextFieldDelegate
}

class CardInfoTextFieldDelegateProxy
    : DelegateProxy<CardInfoTextField, CardInfoTextFieldDelegate>
    , DelegateProxyType
, CardInfoTextFieldDelegate {

    //#MARK: DelegateProxy
    init(parentObject: CardInfoTextField) {
        super.init(parentObject: parentObject, delegateProxy: CardInfoTextFieldDelegateProxy.self)
    }

    public static func registerKnownImplementations() {
        self.register { CardInfoTextFieldDelegateProxy(parentObject: $0) }
    }
}

extension Reactive where Base: CardInfoTextField {
    var delegate: CardInfoTextFieldDelegateProxy {
        return CardInfoTextFieldDelegateProxy.proxy(for: base)
    }

    var didEnterValidInfo: Observable<String> {
        return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterValidInfo:)))
            .map { $0[1] as! String }
    }

    var didEnterPartiallyValidInfo: Observable<String> {
        return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterPartiallyValidInfo:)))
            .map { $0[1] as! String }
    }

    var didEnterOverflowInfo: Observable<String> {
        return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterOverflowInfo:)))
            .map { $0[1] as! String }
    }
}

Once you have the above, you should be able to:

let validInfo: Observable<String> = myCardInfoTextField.rx.didEnterValidInfo
like image 133
Daniel T. Avatar answered Oct 21 '22 08:10

Daniel T.