为类创建通用委托 [英] Create generic delegate for class
问题描述
假设我有一个非常简单的类:
Let's say I have very simple class:
class Box<T> {
var boxedObject:T
init(object: T) {
self.boxedObject = object
}
}
我现在想要实现的是添加委托,它可以通知我框中的值已更改:
What I would like to achieve now is to add delegate, which can inform me that value in box has changed:
protocol BoxDelegate<T>: class {
func valueInBoxChanged(box: Box<T>) -> Void
}
class Box<T> {
var boxedObject: T {
didSet {
self.delegate?.valueInBoxChanged(self)
}
}
weak var delegate: BoxDelegate<T>?
init(object: T) {
self.boxedObject = object
}
}
这段代码当然不起作用,因为我们没有通用委托.我可以让委托成为一个带闭包的结构,但这是一个有点丑陋的解决方案.我应该如何在 Swift 中做这些事情?
This code is of course not working, because we don't have generic delegates. I can make delegate to be a struct with closure, but it's a bit ugly solution. How I should do such things in Swift?
推荐答案
假设你有一个类而不是 BoxDelegate
,我们称之为 Listener
:>
Let say that instead of BoxDelegate
you have a class, and let's call it Listener
:
public typealias ValueChanged <T> = (T) -> Void
public class Listener<T> {
var valueChanged: ValueChanged<T>
public init(_ valueChanged: @escaping ValueChanged<T>) {
self.valueChanged = valueChanged
}
}
Box
现在可以这样写:
class Box<T> {
// the listener needs to be weak in order to be deallocated when the that is
// observing the changes is deallocated
weak private(set) var listener: Listener<T>?
init(_ listener: Listener<T>) {
self.listener = listener
}
}
您现在可以为需要观察其状态的属性创建一个包装类:
and you can now have a wrapper class for the properties whose state you need to observe:
class Observed<T> {
var listeners: [Box<T>] = []
private let queue: DispatchQueue = .main
var value: T {
didSet {
notifyListeners()
}
}
func notifyListeners() {
notifyListeners(value)
}
func notifyListeners(_ value: T) {
queue.async { [weak self] in
self?.listeners.forEach { (box) in
box.listener?.valueChanged(value)
}
}
}
func bind(_ listener: Listener<T>) {
listeners.append(Box(listener))
}
func bind(_ listener: @escaping ValueChanged<T>) -> Listener<T> {
let listener = Listener(listener)
listeners.append(Box(listener))
return listener
}
init(_ value: T) {
self.value = value
}
}
甚至还有一个属性包装器:
and even have a property wrapper:
@propertyWrapper
struct Bind<T> {
let observable: Observed<T>
init(wrappedValue: T) {
observable = Observed(wrappedValue)
}
var wrappedValue: T {
get {
observable.value
}
set {
observable.value = newValue
}
}
var projectedValue: Observed<T> {
observable
}
}
用法:
var text = ""
class ViewModel {
@Bind
var isOn: Bool = false
}
let viewModel = ViewModel()
let bond = viewModel.$isOn.bind { isOn in
if isOn {
text = "on"
} else {
text = "off"
}
}
viewModel.isOn = true
RunLoop.main.run(until: Date().advanced(by: 0.1))
text
viewModel.isOn = false
RunLoop.main.run(until: Date().advanced(by: 0.1))
text
这篇关于为类创建通用委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!