如何将 Delegate 转换为 Observable RxSwift?
How to convert Delegate to Observable RxSwift?
我有委托方法,我需要在 RxSwift 中通过委托代理包装这些方法。我已经使用 Bond 和 Reactive 完成了它,但是在这里,在 RxSwift 中,我无法找到转换它的正确方法。
遵循协议
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)
}
我之前做的是
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)
}
}
}
如何在 RxSwift 中做同样的练习。
我尝试了 DelegateProxy,但不清楚它是如何正确包装它的。
编辑
我删除了以前的代码并将其调整为您想要的解决方案。为了将各种 class 的 "wrap" 委托(主要是 UI)转化为可观察对象,您可以使用 DelegateProxy
class,它是 RxCocoa
的一部分框架。
假设您的 DetailInputTextField
class 有一个 属性 delegate
类型 DetailInputTextFieldDelegate
这是示例:
首先是自定义代理:
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: [=10=]) }
}
}
然后你需要扩展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)
}
}
}
实现 "wrapper" 后,可以这样调用它:
let textField = DetailInputTextField()
textField.rx.didEnterValidInfo
.asObservable()
.subscribe(onNext: { (textField: UITextField, string: String) in
print("Test \(string)")
})
.disposed(by: disposeBag)
我希望它能回答你的问题。
由于这个答案的受欢迎程度,我写了一篇关于它的文章:Convert a Swift Delegate to RxSwift Observables
我相信这是将委托转换为 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: [=10=]) }
}
}
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 { [=10=][1] as! String }
}
var didEnterPartiallyValidInfo: Observable<String> {
return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterPartiallyValidInfo:)))
.map { [=10=][1] as! String }
}
var didEnterOverflowInfo: Observable<String> {
return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterOverflowInfo:)))
.map { [=10=][1] as! String }
}
}
掌握了以上内容后,您应该能够:
let validInfo: Observable<String> = myCardInfoTextField.rx.didEnterValidInfo
我有委托方法,我需要在 RxSwift 中通过委托代理包装这些方法。我已经使用 Bond 和 Reactive 完成了它,但是在这里,在 RxSwift 中,我无法找到转换它的正确方法。
遵循协议
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)
}
我之前做的是
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)
}
}
}
如何在 RxSwift 中做同样的练习。 我尝试了 DelegateProxy,但不清楚它是如何正确包装它的。
编辑
我删除了以前的代码并将其调整为您想要的解决方案。为了将各种 class 的 "wrap" 委托(主要是 UI)转化为可观察对象,您可以使用 DelegateProxy
class,它是 RxCocoa
的一部分框架。
假设您的 DetailInputTextField
class 有一个 属性 delegate
类型 DetailInputTextFieldDelegate
这是示例:
首先是自定义代理:
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: [=10=]) }
}
}
然后你需要扩展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)
}
}
}
实现 "wrapper" 后,可以这样调用它:
let textField = DetailInputTextField()
textField.rx.didEnterValidInfo
.asObservable()
.subscribe(onNext: { (textField: UITextField, string: String) in
print("Test \(string)")
})
.disposed(by: disposeBag)
我希望它能回答你的问题。
由于这个答案的受欢迎程度,我写了一篇关于它的文章:Convert a Swift Delegate to RxSwift Observables
我相信这是将委托转换为 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: [=10=]) }
}
}
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 { [=10=][1] as! String }
}
var didEnterPartiallyValidInfo: Observable<String> {
return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterPartiallyValidInfo:)))
.map { [=10=][1] as! String }
}
var didEnterOverflowInfo: Observable<String> {
return delegate.methodInvoked(#selector(CardInfoTextFieldDelegate.textField(_:didEnterOverflowInfo:)))
.map { [=10=][1] as! String }
}
}
掌握了以上内容后,您应该能够:
let validInfo: Observable<String> = myCardInfoTextField.rx.didEnterValidInfo