委托模式有哪些限制,不能像响应式编程一样实现什么?

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

  1. 为什么我们需要使用Reactive,为什么不仅使用delegate?
  2. delegate不能做到什么Reactive可以做到?
  3. 每种模式的优缺点是什么?

我只知道Reactive是一种功能性编程,也就是声明式编程。


你不需要使用任何响应式库来构建一个符合mvvm模式的应用程序。我也建议你不要仅仅为了这个目的而使用它们。90%的使用RxSwift的项目实际上并不需要它,而且RxSwift只会让它们变得更加复杂。如果你只是想要一个可观察的属性,那么只需在谷歌上搜索可观察的属性包装器,你肯定会找到一些代码行数少于100行的东西。 - Leszek Szary
1个回答

4

对我来说,仅使用委托似乎是实现应用程序逻辑最长的方法。使用响应式编程更加干净,需要更少的代码,并且是一种非常强大的方式。

例如,假设您想要使用RxSwift/RxCocoa和swift 4创建一个响应式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来捕获委托发送的消息。你只需要在你的DelegateProxy类中引用你的PublishSubject,然后在你的视图(ButtonView)中使用该扩展即可。请注意,该扩展是响应式的。

// 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类发送的这些事件。

这与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 反应式代理的工作方式非常相似,他们已经在许多 UIKit 元素上实现了这种方式,例如:https://github.com/ReactiveX/RxSwift/tree/master/RxCocoa/iOS 变得反应式只是非常灵活和强大的,没有必要一直调用代理方法和设置代理。这只会发生一次,想象一下如何处理 viewController 中 CustomViews 的不同组合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接