问题
I'd like to have a generic weak reference to an object and parametrize it by a protocol that is class-bound.
Here is the code example that does not work in my case:
protocol Protocol: class { // also written as `protocol Protocol: AnyObject {`
func function()
}
final class A: Protocol {
func function() {}
}
final class Weak<Type> where Type: AnyObject {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
let a = A()
let something = Weak<Protocol>(property: a) // error: 'Weak' requires that 'Protocol' be a class type
I get an error on last line: 'Weak' requires that 'Protocol' be a class type
.
As Protocol
will always be of class
type (which is the same as AnyObject
) shouldn't that be allowed by the compiler?
Is it possible to resolve that issue with swift 4?
If not, is it a limitation that can be resolved in a future version of swift or is it something impossible that the type system can not allow to happen?
A not accepted solution is to use @objc
to the protocol declaration as in:
@obc protocol Protocol: class {
func function()
}
as this leads to limitations.
回答1:
You are saying:
final class Weak<Type> where Type: AnyObject {
So you yourself are requiring that Type be a class (because that is exactly what AnyObject means).
A protocol is not a class. It is a protocol.
回答2:
This is currently impossible because protocols do not conform to themselves. A protocol is not a type; it is a recipe for a type. As the simplest example of why this is hard, consider this situation:
protocol X {
init()
}
func f<T: X>(type: T.Type) -> T {
return type.init()
}
f(type: X.self)
This would create a value of type X
, but would that be? This isn't allowed, and the mechanism that prevents it is that protocols do not conform to themselves. This crops up in a lots of other ways, and your example is one of them.
Some of this will be addressed when more of the Generics Manifesto is implemented, particularly the section Generalized Existentials, but currently what you want isn't possible. You can't have a "weak reference to some unknown thing." You need to know what that thing is.
The standard solution to this problem is a box, not a protocol. See Weak Arrays for an example.
回答3:
If I understand your problem I design this solution
First I created a protocol
called WeakProtocol
, this will be our base of protocols
protocol WeakProtocol : AnyObject {}
After change your protocol to extends this new WeakProtocol
protocol Protocol: WeakProtocol {
func function()
}
after your Weak
class you need apply a WeakProtocol
type example
final class Weak<Type> where Type: WeakProtocol {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
Now to implement you don't need say it Protocol because the constructor receive the protocol.
Complete code is
protocol WeakProtocol : AnyObject {}
protocol Protocol: WeakProtocol {
func function()
}
final class A: Protocol {
func function() {}
}
final class Weak<Type> where Type: WeakProtocol {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
let a = A()
let something = Weak(property: a)
You can too only change Protocol
to extends AnyObject
and Weak
class to Type:Protocol
, like this
protocol Protocol: AnyObject {
func function()
}
final class A: Protocol {
func function() {}
}
final class Weak<Type> where Type: Protocol {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
let a = A()
let something = Weak(property: a)
来源:https://stackoverflow.com/questions/51541353/generic-class-with-class-bound-constraint-cannot-be-parametrized-by-class-bound