簡體   English   中英

如何將委托轉換為可觀察的 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 但不清楚它是如何正確包裝它的。

由於這個答案很受歡迎,我寫了一篇關於它的文章: 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: $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 }
    }
}

完成上述操作后,您應該能夠:

let validInfo: Observable<String> = myCardInfoTextField.rx.didEnterValidInfo

編輯

我已經刪除了我以前的代碼並將其調整為您想要的解決方案。 為了將各種類(主要是 UI)的委托“包裝”到 observable 中,您可以使用DelegateProxy類,它是RxCocoa框架的一部分。

假設您的DetailInputTextField類具有類型為DetailInputTextFieldDelegate的屬性delegate ,示例如下:

首先是自定義代理:

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) }
    }
}

然后,您需要擴展Reactive ,您可以在其中添加與委托方法對應的所有 observable:

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)
        }
    }
}

當你實現了“包裝器”時,你可以這樣稱呼它:

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

我希望它能回答你的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM