gpt4 book ai didi

swift - 为类创建通用委托(delegate)

转载 作者:搜寻专家 更新时间:2023-10-31 21:47:57 25 4
gpt4 key购买 nike

假设我有一个非常简单的类:

class Box<T> {
var boxedObject:T

init(object: T) {
self.boxedObject = object
}
}

我现在想实现的是添加委托(delegate),它可以通知我框中的值已更改:

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

这段代码当然是行不通的,因为我们没有通用委托(delegate)。我可以让委托(delegate)成为一个带有闭包的结构,但这是一个有点难看的解决方案。我应该如何在 Swift 中做这些事情?

最佳答案

假设您有一个类而不是BoxDelegate,我们称它为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
}
}

现在您可以为需要观察其状态的属性创建一个包装类:

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

甚至有一个属性包装器:

@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

In a playground

关于swift - 为类创建通用委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36130015/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com