【问题标题】:What delegate cant do than Reactive?什么代表不能比 Reactive 做?
【发布时间】:2018-02-07 21:20:47
【问题描述】:

在过去的两年里,我使用 MVVM 模式构建应用程序,每个教程都说 MVVM 使用 Reactive 库,例如:RXSwift 或 ReactiveCocoa,因为我是 iOS 程序员。我才意识到

  1. 为什么我们需要使用 Reactive,为什么我们不使用委托?
  2. 代理不能对 Reactive 做什么?
  3. 每种模式的优缺点?

我只知道 Reactive 是函数式编程,即声明式编程。

【问题讨论】:

  • 您不需要使用任何响应式库来构建具有 mvvm 模式的应用程序。我还建议不要仅为此使用它们中的任何一个。 90% 使用 RxSwift 的项目不应该真正使用它,而 RxSwift 只会使它们复杂化。如果你只是想要一个 observable,那么只需在 google 上搜索 observable 属性包装器,你肯定会找到少于 100 行代码的东西。

标签: ios swift mvvm


【解决方案1】:

对我来说,单独使用委托似乎是实现应用程序逻辑的最长方法。响应式更简洁,需要更少的代码,并且是一种非常强大的做事方式。

举个例子,假设你想使用 RxSwift/RxCocoa 和 swift 4 创建一个 Reactive ButtonTap 系统:

1) 您创建一个协议,该协议的实现方式与创建普通委托抽象类时的实现方式相同。请注意,我们符合@objc

import RxSwift
import RxCocoa

// MARK: - ButtonTap Delegate protocol
@objc public protocol ButtonTapDelegate: NSObjectProtocol {
    @objc func button(didSelect view: UIView, at index: Int)
}

2) DelegateProxyType 类是发生反应的地方。就像您有一个从您的委托 (ButtonTapDelegate) 派生的类一样,该类不仅可以做到这一点,还可以使用 PublishSubject 处理您的委托消息。

// MARK: - ButtonTap DelegateProxy
open class ButtonTapDelegateProxy: DelegateProxy<UIView, ButtonTapDelegate>,
DelegateProxyType, ButtonTapDelegate {

    /// Typed parent object.
    public weak private(set) var buttonView: UIView?

    internal var didSelectSubject = PublishSubject<(view: UIView, index: Int)>()

    // MARK: - parent object for delegate proxy.
    public init(parentObject: UIView) {
        self.buttonView = parentObject
        super.init(parentObject: parentObject, delegateProxy: ButtonTapDelegateProxy.self)
    }

    // MARK: - Register known implementationss. (from DelegateProxyType)
    public static func registerKnownImplementations() {
        self.register { ButtonTapDelegateProxy(parentObject: $0) }
    }

    // MARK: - read the current delegate. (from DelegateProxyType)
    public class func currentDelegate(for object: UIView) -> ButtonTapDelegate? {
        return object.delegate
    }

    // MARK: - set the current delegate. (from DelegateProxyType)
    public class func setCurrentDelegate(_ delegate: ButtonTapDelegate?, to object: UIView) {
        object.delegate = delegate as? ButtonTapDelegateProxy
    }

    // MARK: delegate method
    public func button(didSelect view: UIView, at index: Int) {
        didSelectSubject.onNext((view, index))
    }

    // MARK: - dispose the publish subject 
    deinit {
        didSelectSubject.on(.completed)
    }
}

3) 然后,只需在具有委托属性的地方创建自定义按钮类。您可以通过调用其抽象方法简单地将消息传递给您的委托。

// MARK: - create Custom ButtonView class with the delegate property
open class ButtonView: UIView {
    @IBOutlet weak open var delegate: ButtonTapDelegate?

    func tapButtonAction() {
        let view = UIView()
        let index = 2
        delegate.button(didSelect: view, at: index)
    }

}

// MARK: - ButtonView must have delegate property
extension ButtonView: HasDelegate {
    public typealias Delegate = ButtonTapDelegate
}

4) 您可以使用 RxCocoa 捕获代理发送的消息。您只需使用视图的此扩展(ButtonView)从您的 DelegateProxy 类中引用您的 PublishSubject。请注意,扩展是响应式的

// MARK: - Custom ButtonView with the Reactive delegate and its protocol function
 public extension Reactive where Base: ButtonView {

    /// Reactive wrapper for `delegate`.
    /// For more information take a look at `DelegateProxyType` protocol documentation.
    fileprivate var delegate: ButtonTapDelegateProxy {
        return ButtonTapDelegateProxy.proxy(for: base)
    }

    public func setDelegate(_ delegate: ButtonTapDelegate) -> Disposable {
        return ButtonTapDelegateProxy
        .installForwardDelegate(delegate, retainDelegate: false, onProxyForObject: self.base)
    }

    public var didSelect: ControlEvent<(view: UIView, index: Int)> {
        return ControlEvent(events: delegate.didSelectSubject)
    }
}

5) 在您的 ViewController 中,您将使用 RxSwift 监听任何按钮点击,并在您的 DelegateProxy 类中捕获 PublishSubject 发送的那些事件。 这与 RxSwift 手势示例没有什么不同:https://github.com/RxSwiftCommunity/RxGesture

class myViewController: UIViewController {

    @IBOutlet weak var buttonView: ButtonView!

    override func viewDidLoad() {
         super.viewDidLoad

         buttonView.rx.didSelect.asObservable()
            .subscribe(onNext: { view, index in
             // button tapped in view at index
        }).disposed(by: bag)
    }

}

这个过程与所有 RxSwift 和 RxCocoa Reactive 委托的工作方式非常相似,他们已经在许多 UIKit 元素上实现了这一点,例如:https://github.com/ReactiveX/RxSwift/tree/master/RxCocoa/iOS

响应式是非常灵活和强大的,不需要一直调用委托方法和设置委托。这只会发生一次,想象一下如何在 viewController 中处理自定义视图的不同组合。

【讨论】:

    猜你喜欢
    • 2016-11-20
    • 2011-08-23
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多