对我来说,仅使用委托似乎是实现应用程序逻辑最长的方法。使用响应式编程更加干净,需要更少的代码,并且是一种非常强大的方式。
例如,假设您想要使用RxSwift/RxCocoa和swift 4创建一个响应式ButtonTap系统:
1)创建一个协议,其实现方式与创建普通委托抽象类时相同。请注意,我们符合@objc
import RxSwift
import RxCocoa
@objc public protocol ButtonTapDelegate: NSObjectProtocol {
@objc func button(didSelect view: UIView, at index: Int)
}
2) DelegateProxyType类是响应式编程的核心。就像您从委托(ButtonTapDelegate)派生出一个类一样,这个类不仅这样做,而且还使用PublishSubject处理委托消息。
open class ButtonTapDelegateProxy: DelegateProxy<UIView, ButtonTapDelegate>,
DelegateProxyType, ButtonTapDelegate {
public weak private(set) var buttonView: UIView?
internal var didSelectSubject = PublishSubject<(view: UIView, index: Int)>()
public init(parentObject: UIView) {
self.buttonView = parentObject
super.init(parentObject: parentObject, delegateProxy: ButtonTapDelegateProxy.self)
}
public static func registerKnownImplementations() {
self.register { ButtonTapDelegateProxy(parentObject: $0) }
}
public class func currentDelegate(for object: UIView) -> ButtonTapDelegate? {
return object.delegate
}
public class func setCurrentDelegate(_ delegate: ButtonTapDelegate?, to object: UIView) {
object.delegate = delegate as? ButtonTapDelegateProxy
}
public func button(didSelect view: UIView, at index: Int) {
didSelectSubject.onNext((view, index))
}
deinit {
didSelectSubject.on(.completed)
}
}
3) 然后,在您拥有委托属性的自定义按钮类中创建该类。您可以通过调用其抽象方法向委托传递消息。
open class ButtonView: UIView {
@IBOutlet weak open var delegate: ButtonTapDelegate?
func tapButtonAction() {
let view = UIView()
let index = 2
delegate.button(didSelect: view, at: index)
}
}
extension ButtonView: HasDelegate {
public typealias Delegate = ButtonTapDelegate
}
4) 你可以使用RxCocoa来捕获委托发送的消息。你只需要在你的DelegateProxy类中引用你的PublishSubject,然后在你的视图(ButtonView)中使用该扩展即可。请注意,该扩展是响应式的。
public extension Reactive where Base: ButtonView {
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
}).disposed(by: bag)
}
}
这个过程与所有 RxSwift 和 RxCocoa 反应式代理的工作方式非常相似,他们已经在许多 UIKit 元素上实现了这种方式,例如:
https://github.com/ReactiveX/RxSwift/tree/master/RxCocoa/iOS
变得反应式只是非常灵活和强大的,没有必要一直调用代理方法和设置代理。这只会发生一次,想象一下如何处理 viewController 中 CustomViews 的不同组合。