testing protocol conformance with associated types

2020-06-18 10:43发布

问题:

I have a protocol that uses an associated type, as such:

protocol Populatable {
    typealias T
    func populateWith(object: T)
}

and classes that implement the protocol:

class DateRowType: Populatable {
    func populateWith(object: NSDate) {
        print(object.description)
    }
}

class StringRowType : Populatable {
    func populateWith(object: String) {
        print(object)
    }
}

but when I try to cast or test for conformance, like this:

let drt = DateRowType()
let srt = StringRowType()

let rowTypes = [drt, srt]
let data = [NSDate(), "foo"]

for (i, p: Populatable) in enumerate(rowTypes) {
    p.populateWith(data[i])
}

I get the error:

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

What's the correct way to test if the object conforms to the Populatable protocol?

Note: all the code required to try this out is contained in the question, just copy the code blocks into a playground.

回答1:

As the error says, you cannot cast it to Populatable here. I think the correct way is to cast it to EventRowType.

if let rowController = self.table.rowControllerAtIndex(i) as? EventRowType {

And you already tested that 'EventRowType' class conforms 'Populatable' protocol. Because if the EventRowType doesn't have function named 'populate', swift compiler says,

Type 'EventRowType' does not conform to protocol 'Populatable'



回答2:

I don't think you will be able to go generic the whole way, unless possibly by using AnyObject and testing the class of the parameter in each populateWith function.

But this will work:

for (i, p) in enumerate(rowTypes) {
    if let dateRow = p as? DateRowType {
        dateRow.populateWith(data[i] as! NSDate)
    }
    else if let stringRow = p as? StringRowType {
        stringRow.populateWith(data[i] as! String)
    }
}

You will just need to expand this for every Populatable class you add.