我有一个类需要在其中一个属性更改时调用委托.以下是委托的简化类和协议:
protocol MyClassDelegate: class {
func valueChanged(myClass: MyClass)
}
class MyClass {
weak var delegate: MyClassDelegate?
var currentValue: Int {
didSet {
if let actualDelegate = delegate {
actualDelegate.valueChanged(self)
}
}
}
init(initialValue: Int) {
currentValue = initialValue
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都很好.但是,我想让这个类变得通用.所以,我试过这个:
protocol MyClassDelegate: class {
func valueChanged(genericClass: MyClass)
}
class MyClass<T> {
weak var delegate: MyClassDelegate?
var currentValue: T {
didSet {
if let actualDelegate = delegate {
actualDelegate.valueChanged(self)
}
}
}
init(initialValue: T) {
currentValue = initialValue
}
}
Run Code Online (Sandbox Code Playgroud)
这会引发两个编译器错误.首先,valueChanged
协议中声明的行给出:Reference to generic type 'MyClass' requires arguments in <...>
.其次,调用valueChanged
在didSet
观察者抛出:'MyClassDelegate' does not have a member named 'valueChanged'
.
我以为使用a typealias
会解决问题:
protocol MyClassDelegate: class {
typealias MyClassValueType
func valueChanged(genericClass: MyClass<MyClassValueType>)
}
class MyClass<T> {
weak var delegate: MyClassDelegate?
var currentValue: T {
didSet {
if let actualDelegate = delegate {
actualDelegate.valueChanged(self)
}
}
}
init(initialValue: T) {
currentValue = initialValue
}
}
Run Code Online (Sandbox Code Playgroud)
我似乎在正确的道路上,但我仍然有两个编译器错误.上面的第二个错误仍然存在,以及声明delegate
属性的新行MyClass
:Protocol 'MyClassDelegate' can only be used as a generic constraint because it has Self or associated type requirements
.
有没有办法实现这个目标?
Aar*_*sen 39
如果没有更多信息,很难知道问题的最佳解决方案是什么,但一种可能的解决方案是将协议声明更改为:
protocol MyClassDelegate: class {
func valueChanged<T>(genericClass: MyClass<T>)
}
Run Code Online (Sandbox Code Playgroud)
这消除了typealias
协议中a的需要,并且应该解决您已经获得的错误消息.
我不确定这是否是最适合您的解决方案的部分原因是因为我不知道valueChanged
函数的调用方式和位置,因此我不知道添加泛型参数是否切实可行那个功能.如果此解决方案不起作用,请发表评论.
协议可以有类型要求,但不能是通用的;有类型要求的协议可以用作通用约束,但不能用于键入值。因此,如果您选择此路径,您将无法从泛型类中引用协议类型。
如果您的委托协议非常简单(例如一两个方法),您可以接受闭包而不是协议对象:
class MyClass<T> {
var valueChanged: (MyClass<T>) -> Void
}
class Delegate {
func valueChanged(obj: MyClass<Int>) {
print("object changed")
}
}
let d = Delegate()
let x = MyClass<Int>()
x.valueChanged = d.valueChanged
Run Code Online (Sandbox Code Playgroud)
您可以将这个概念扩展到包含一堆闭包的结构:
class MyClass<T> {
var delegate: PseudoProtocol<T>
}
struct PseudoProtocol<T> {
var valueWillChange: (MyClass<T>) -> Bool
var valueDidChange: (MyClass<T>) -> Void
}
Run Code Online (Sandbox Code Playgroud)
不过,在内存管理时要格外小心,因为块对它们所引用的对象具有强引用。相反,委托通常是弱引用以避免循环。