Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class-only generic constraints in Swift

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

like image 908
lassej Avatar asked Mar 05 '15 18:03

lassej


People also ask

What is generic constraints in Swift?

Generics in Swift allows you to write generic and reusable code, avoiding duplication. A generic type or function creates constraints for the current scope, requiring input values to conform to these requirements.

Can only be used as a generic constraint?

Protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements.

Can a generic class have multiple constraints?

Multiple interface constraints can be specified. The constraining interface can also be generic.


1 Answers

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>()
like image 70
Airspeed Velocity Avatar answered Oct 15 '22 07:10

Airspeed Velocity