JoshParadroid JoshParadroid - 2 months ago 11
Swift Question

How do a conform to a protocol that declares property of type protocol?

I'm trying to create a protocol and a couple of classes that conform to it. The protocol has an property which conforms to another protocol so the classes each need to have a property that matches.

This is (something like) what I'm trying so far:

protocol Edible {
func eat()
}

class Apple:Edible {
func eat() {
print("Crunch")
}
}

class Banana:Edible {
func eat() {
print("Homph")
}
}

protocol Delicious {
func consume()

var fruit: Edible? { get set }
}

class ToffeeApple: Delicious {
func consume() {
print("I like toffee apples!")
fruit.eat()
// ...
}

var fruit: Apple?
}

class BananaSplit: Delicious {
func consume() {
print("Ah! A banana split!")
fruit.eat()
// ....
}

var fruit: Banana?
}


The (relevant) error I'm getting is "Type 'ToffeeApple' does not conform to protocol 'Delicious'" (and the same for Banana and BananaSplit too). I thought the properties
Apple
and
Banana
would satisfy the requirements as they both conform to
Edible
as as
fruit
does. Am I declaring one of these incorrectly or is this not possible?

Many thanks.

Answer

Simply change from:

protocol Delicious {
    func consume()

    var fruit: Edible? { get set }
}

to:

protocol Delicious {
    func consume()

    associatedtype EdibleType: Edible
    var fruit: EdibleType? { get set }
}

associatedtype EdibleType: Edible means:

protocol Delicious has an unprovided type EdibleType which confirm to protocol Edible.

And the type should be provided when something is confirm to Delicious.

So in:

class ToffeeApple: Delicious {
    func consume() {
        print("I like toffee apples!")
        fruit.eat()
        // ...
    }

    typealias EdibleType = Apple
    var fruit: Apple?
}

The EdibleType is filled with Type Apple,

And in:

class BananaSplit: Delicious {
    func consume() {
        print("Ah! A banana split!")
        fruit.eat()
        // ....
    }

    typealias EdibleType = Banana
    var fruit: Banana?
}

The EdibleType is filled with Type Banana,

If you want learn more about this you can search around Swift Generics.