Class-only generic constraints in Swift

2019-03-14 12:44发布

问题:

I'm trying to mark a variable of a generic type as weak:

class X<T> {
  weak var t: T?
}

If I don't put in any constraints for T I get the error weak cannot be applied to non-class type 'T'.

If I would only use use this with NSObject derived classes this would work:

class X<T: NSObject> {
  weak var t: T?
}

But I also want to be able to use pure Swift classes.

For protocols it is possible to require that the implementor is of class type by using the class keyword:

protocol ClassType: class {
}

With the ClassType protocol I can now mark the variable as weak:

class X<T: ClassType> {
  weak var t: T?
}

But I cannot add the class keyword directly to the generic parameter:

class X<T: class> { // Compile error
  weak var t: T?
}

I can make the protocol solution work for all NSObject derived classes with an extension:

extension NSObject: ClassType {
}

But for pure Swift classes there is no common superclass that I could add this extension to. Is there a way to make this work without adding the ClassType protocol to each class I want to use the X class with? E.g. some special qualifier for the generic parameter like class X<T:ThisIsAClass>?

回答1:

You want AnyObject, which the Swift docs describe as:

The protocol to which all classes implicitly conform.

class X<T: AnyObject> {
    weak var t: T?
}

class C { }
let x = X<C>()  // works fine
x.t = C()  

// error: type 'Int' does not conform to protocol ‘AnyObject’
// (because Int is a struct)
let y = X<Int>()