How to convert Delegate to Observable RxSwift?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



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.





If you're using RxSwift (observation) why do you want to keep on using delegation at all?
– Au Ris
Aug 13 at 8:12





So, where delegate methods of some class with be called or assigned?
– Sam Shaikh
Aug 13 at 9:15





if you observer Q, there are four delegates, and need them to be used, in main controller, by wrapping, but how we can do same here in Rx?
– Sam Shaikh
Aug 13 at 9:19




2 Answers
2



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





Bloody hell. The key to this is to define the delegate method as optional, it also relies on objective-c run time so that means you can't use enums in your method.
– Pavan
Aug 23 at 11:15




EDIT



I've removed my previous code and adjusted it to your desired solution. In order to "wrap" delegates of various classes (mostly UI) into observables you can use DelegateProxy class which is a part of RxCocoa framework.


DelegateProxy


RxCocoa



Assuming your DetailInputTextField class has a property delegate of type DetailInputTextFieldDelegate here is the example:


DetailInputTextField


delegate


DetailInputTextFieldDelegate



First the custom proxy:


import RxSwift
import RxCocoa

extension DetailInputTextField: HasDelegate
public typealias Delegate = DetailInputTextFieldDelegate


open class DetailInputTextFieldDelegateProxy
: DelegateProxy<DetailInputTextField, DetailInputTextFieldDelegate>
, DelegateProxyType
, DetailInputTextFieldDelegate

/// Typed parent object.
public weak private(set) var textField: DetailInputTextField?

/// - parameter webView: Parent object for delegate proxy.
public init(textField: ParentObject)
self.textField = textField
super.init(parentObject: textField, delegateProxy: DetailInputTextFieldDelegateProxy.self)


// Register known implementations
public static func registerKnownImplementations()
self.register DetailInputTextFieldDelegateProxy(textField: $0)




Then you need to extend Reactive where you can add all the observables corresponding to delegate methods:


Reactive


extension Reactive where Base: DetailInputTextField
public var delegate: DelegateProxy<DetailInputTextField, DetailInputTextFieldDelegate>
return DetailInputTextFieldDelegateProxy.proxy(for: base)


public var didEnterValidInfo: Observable<(UITextField,String)>
return delegate
.methodInvoked(#selector(DetailInputTextFieldDelegate.textField(_:didEnterValidInfo:)))
.map params in
// Parameters is an array, be sure you cast them correctly
return (params[0] as! UITextField, params[1] as! String)





When you have the "wrapper" implemented, you can call it like this:


let textField = DetailInputTextField()
textField.rx.didEnterValidInfo
.asObservable()
.subscribe(onNext: (textField: UITextField, string: String) in
print("Test (string)")
)
.disposed(by: disposeBag)



I hope it answers your question.





This DetailInputTextField is not mine class. Its declared already somewhere in library, so won't it effect? secondly what is delegate, its not identifying it
– Sam Shaikh
Aug 13 at 10:26





If DetailInputTextField is not your class then you should not add code to it. I will update my answer.
– Au Ris
Aug 13 at 11:13


DetailInputTextField





Sure, I am waiting, I made something like extension Reactive where Base: DetailInputTextField public var dataSource: DelegateProxy<DetailInputTextField, CardInfoTextFieldDelegate> return RxDetailInputTextFieldProxy.proxy(for: base) /// For more information take a look at DelegateProxyType. open class RxDetailInputTextFieldProxy : DelegateProxy<DetailInputTextField, CardInfoTextFieldDelegate> , DelegateProxyType , CardInfoTextFieldDelegate { But it seems unclear yet.
– Sam Shaikh
Aug 13 at 11:19


DelegateProxyType





Please check my updated answer. Initially I had a another way in mind, but this was an interesting exercise for me too.
– Au Ris
Aug 13 at 13:02






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

make 2 or more post in bootsrap

Store custom data using WC_Cart add_to_cart() method in Woocommerce 3

Firebase Auth - with Email and Password - Check user already registered