I've been playing around with Swift protocols and I'm trying to figure out why this code isn't working...
protocol Animal {
var name: String {get}
var breed: String {get}
}
struct Bird: Animal {
var name: String
var breed: String
var wingspan: Double
}
protocol AnimalHouse {
var myAnimal: Animal! {get set}
}
class Birdhouse: AnimalHouse {
var myAnimal: Bird!
func isOpeningBigEnough() -> Bool {
return myAnimal.wingspan <= 5.0
}
}
The problem the compiler keeps giving me is that that BirdHouse doesn't conform to protocol AnimalHouse. If you follow up, it'll tell you that myAnimal requires type Animal, and I'm supplying type Bird. Obviously, Bird does conform to the Animal protocol, but that's not enough to make the compiler happy.
I'm assuming this is one of those one-line fixes where the trick is knowing where the one line is. Anybody have any suggestions?
(And, yes, I could make myAnimal an Animal and then cast it as a Bird later in the function, but that seems unnecessarily messy.)
The compiler is right.
When you write
protocol AnimalHouse {
var myAnimal: Animal! {get set}
}
you are making (among the others) the following statement:
If a type does conform to
AnimalHouse, then it is possible to put anAnimal!inside themyAnimalproperty.
Now let's look at how Birdhouse is defined
class Birdhouse: AnimalHouse {
var myAnimal: Bird!
...
}
The type on myAnimal is Bird!.
And you cannot put an Animal! inside a property of type Bird!.
So Birdhouse does not respect what promised in the AnimalHouse protocol.
As you said yourself in the question, you can't just downcast to Bird from Animal. I propose changing the var to be optional, as an AnimalHouse is likely to be without inhabitant some of the time.
In my implementation below non Bird animals can't enter the birdhouse.
protocol AnimalHouse {
var myAnimal: Animal? {get set}
}
class Birdhouse: AnimalHouse {
var myAnimal: Animal? {
get{
return myBird
}
set(newanimal){
if let bird = newanimal as? Bird {
myBird = bird
}
}
}
private var myBird: Bird?
func isOpeningBigEnough() -> Bool {
return myBird?.wingspan <= 5.0
}
}
A further development of the AnimalHouse protocol might be to add throws to the setter (not possible as of Swift 2.0) or that an AnimalHouse returns the type of animal it can house.
protocol AnimalHouse {
var myAnimal: Animal? {get set}
func houses() -> Any
}
class Birdhouse: AnimalHouse {
func houses() -> Any {
return Bird.self
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With