Search code examples
swiftoption-typeoptional-chaining

Optional downcasting to another type if the first one fails


I have a class with a delegate of type UIViewController

This delegate can be one of 2 subclasses of UIViewController. Both subclasses contain a method with the same name taking the same arguments.

class TypeOne: UIViewController {
    method() {

    }
}

class TypeTwo: UIViewController {
    method() {

    }
}

Currently I'm writing the statement like this and of course it works, but it's driving me batty from a DRY standpoint.

if let delegate = delegate as? TypeOne {
    delegate.method()
} else if let delegate = delegate as? TypeTwo {
    delegate.method()
}

I want to do something like

if let delegate = delegate as? TypeOne ?? delegate as TypeTwo {
    delegate.method()
}

But the above doesn't actually downcast the delegate, as I get an error that type UIViewController doesn't contain 'method'

How else can I chain this so if the first downcast fails, the second one is tried and the delegate is treated as either type rather than a base UIViewController?


Solution

  • You are describing a protocol:

    protocol MethodHolder {
        func method()
    }
    class TypeOne: UIViewController, MethodHolder {
        func method() {
        }
    }
    class TypeTwo: UIViewController, MethodHolder {
        func method() {
        }
    }
    class ActualViewController : UIViewController {
        var delegate : MethodHolder?
        override func viewDidLoad() {
            super.viewDidLoad()
            self.delegate?.method() // no need to cast anything!
        }
    }
    

    There is no need to cast anything, because typing the delegate as a MethodHolder guarantees to the compiler (and to you) that this object has a method method. Thus you can call that method without bothering to know whether this happens to be a TypeOne or a TypeTwo.