Search code examples
swiftdowncast

Declaring first, downcasting later


Say I have BaseClass, DerivedClassOne, DerivedClassTwo, a magical factory method giveMeAnObjectOfType(type: String) -> BaseClass, and the following code

func myBeautifulFunction(index: Int) -> BaseClass {
    let type : String = self.someArray[index]
    var anObject : BaseClass

    switch type {

    case "TypeOne":
        // This won't work
        anObject = self.giveMeAnObjectOfType("DerivedClassOne") as! DerivedClassOne
        anObject.methodOfDCOne()

    case "TypeTwo":
        // Neither will this
        anObject = self.giveMeAnObjectOfType("DerivedClassTwo") as! DerivedClassTwo
        anObject.methodOfDCTwo()

    default:
        // Throw a tantrum here
    }

    return anObject
}

This will result in errors saying that anObject does not contain either methodOfDCOne() or methodOfDCTwo(). Question: how do I cast my objects properly?

Basically, I could achieve the same by having several return statements within the switch's cases, but I don't like how that looks. Besides, if I wanted to call some methods of BaseClass, I'd have tons of repeated code.


Solution

  • anObject.methodOfDCOne()
    

    does not compile because methodOfDCOne is not an instance method of BaseClass (or its superclasses).

    You have to create objects of the subclass type first so that you can call the subclass methods. Then assign (upcast) the object to the base class variable:

    func myBeautifulFunction(index: Int) -> BaseClass {
        let type : String = self.someArray[index]
        let anObject : BaseClass
    
        switch type {
    
        case "TypeOne":
            let dc1 = self.giveMeAnObjectOfType("DerivedClassOne") as! DerivedClassOne
            dc1.methodOfDCOne()
            anObject = dc1
    
        case "TypeTwo":
            let dc2 = self.giveMeAnObjectOfType("DerivedClassTwo") as! DerivedClassTwo
            dc2.methodOfDCTwo()
            anObject = dc2
    
        default:
            // Throw a tantrum here
            fatalError("Unexpected type")
        }
    
        return anObject
    }