Swift protocol conform: Candidate has non-matching type

You can avoid pushing the knowledge of the array element class up to the protocol by using a type alias requirement:

protocol TestProtocol 
{
    typealias ArrayElement: AnyObject
    var prop: [ArrayElement] {get}
}

class Test: TestProtocol 
{
    typealias ArrayElement  = SomeClass
    var prop:[ArrayElement] = []    //No compiler error
}

A playground example of what you can do:

class SomeClass {

}

class Subclass : SomeClass{

}

protocol TestProtocol {
  typealias T : SomeClass
  var prop: [T] {get}
}

class Test: TestProtocol {
  var prop = [Subclass]()

  func test(){
    prop.append(Subclass())
  }
}

let test = Test()
test.test() 
print(test.prop) // prints "[Subclass]\n"

The array is an unnecessary complication, so let's remove it and just think about a simple type. This is not legal:

protocol TestProtocol {
    var prop: AnyObject {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop : SomeClass = SomeClass() // error
}

The problem is that the protocol declaration says quite literally that whoever claims to adopt TestProtocol must have a property prop of type AnyObject — not of some type that merely conforms to AnyObject.

If you find this surprising, you may be confusing instances of types with types themselves. It is true that an instance of SomeClass can be used where an instance of AnyObject is expected. But types themselves do not work this way; you cannot substitute the type SomeClass when the protocol demands the type AnyObject.

To see this more clearly, note that this does compile just fine:

protocol TestProtocol {
    var prop: AnyObject {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop : AnyObject = SomeClass() // changing the declared _type_
}

That compiles, as you already discovered; but, as you have also said, it is not what you wanted. So how to do what you want?

Well, in Swift, the way you express the notion of specifying a type that conforms to a protocol type is through a generic with a constraint. That is what the answers you've been given do. A typealias in a protocol declaration can be a way of making a generic protocol. And a generic can have a constraint, saying e.g. that the type in question should conform to a protocol or inherit from a class. Thus, this is legal and is the sort of solution you're looking for:

protocol TestProtocol {
    typealias T:AnyObject // generic
    var prop: T {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop : SomeClass = SomeClass() // :)
}

The line typealias T:AnyObject says that T must be a type that conforms to AnyObject, which is precisely what you are trying to say.

Tags:

Ios

Swift