Home » Swift » Protocol inheritance + delegates in Swift

Protocol inheritance + delegates in Swift

Posted by: admin January 9, 2018 Leave a comment

Questions:

I have a class with a delegate. I create a subclass, which also has a delegate. I wanted to let the protocol used for the second delegate extend the protocol used for first delegate:

protocol MySuperClassProtocol {
    func foo()
}

class MySuperClass {
    var delegate:MySuperClassProtocol?
}

protocol MySubClassProtocol:MySuperClassProtocol {
    func bar()
}

class MySubClass: MySuperClass {
    override var delegate:MySubClassProtocol? // compiler error - "cannot override..."

    func test() {
        delegate?.foo()
        delegate?.bar()
    }
}

class UserClass:MySubClassProtocol {
    func foo() {
        println("foo!")
    }
    func bar() {
        println("bar")
    }
} 

Is there a way to solve this? The only possible solution I see is to make the 2 protocols independent of each other, and use different names. Like this:

protocol MySuperClassProtocol {
    func foo()
}

class MySuperClass {
    var mySuperClassDelegate:MySuperClassProtocol?
}

protocol MySubClassProtocol {
    func bar()
}

class MySubClass: MySuperClass {
    var mySubClassDelegate:MySubClassProtocol?

    func test() {
        mySuperClassDelegate?.foo()
        mySubClassDelegate?.bar()
    }
}

class UserClass:MySuperClassProtocol, MySubClassProtocol {
    func foo() {
        println("foo!")
    }
    func bar() {
        println("bar")
    }
}

But this looks a bit weird + will not let me use naming convention for delegate- “delegate”.

Answers:

I was trying to find an ideal solution to this for some time, but could not come up with anything better that this:

protocol BaseDelegateProtocol: class { }

class BaseDelegate: BaseDelegateProtocol { }

class BaseActor {
    weak var delegate: BaseDelegate? = nil
}

// MARK: -

protocol ConcreteDelegateProtocol: class {
    func doSomething()
}

class ConcreteDelegate: BaseDelegate, ConcreteDelegateProtocol {
    func doSomething() {
        // Do something
    }
}

class ConcreteActor: BaseActor {
    private weak var concreteDelegate: ConcreteDelegateProtocol? = nil

    override var delegate: BaseDelegate? {
        didSet {
            concreteDelegate = delegate as? ConcreteDelegateProtocol
        }
    }
}

Above works in XCode 7 / Swift 2.

  • This pattern allows adopting more and more protocols on the way down inheriting from BaseDelegate.
  • There is no need to inherit protocols one from the other, which helps keeping things isolated.
  • didSet observer on delegate property is automatically called for superclasses, therefore no need to call super.<blah> explicitly, and no risk to ‘forget’ doing so
  • Concrete delegate properties can be kept private on each level of inheritance, thereby reducing the clutter.
Questions:
Answers:

Sorry for necroposting, the only one solution i found is:

protocol SuperClassDelegate {
    func first_method()
}

class SuperClass {
    var delegate: SuperClassDelegate?

    func do_something() {
        delegate?.first_method()
    }
}

protocol SubClassDelegate: SuperClassDelegate {
    func second_method()
}

class SubClass: SuperClass {
    private var subDelegate: SubClassDelegate?
    override var delegate: SuperClassDelegate? {
        get { return self.subDelegate }
        set { self.subDelegate = newValue as! SubClassDelegate? }
    }

    //override func do_something() {
    //  super.do_something()
    //  subDelegate?.second_method()
    //}

    func do_something_other() {
        //subDelegate?.first_method()
        self.do_something()
        subDelegate?.second_method()
    }
}

class InheritanceAndDelegation: SubClassDelegate {
    let obj = SubClass()

    init() {
        obj.delegate = self
    }

    internal func first_method() {
        print("Hello from SuperClass")
    }

    internal func second_method() {
        print("Hello from SubClass")
    }

    func check() {
        obj.do_something_other()
    }
}

let inheritanceAndDelegation = InheritanceAndDelegation()
inheritanceAndDelegation.check()
//prints:
//Hello from SuperClass
//Hello from SubClass

Commented code works too. Hope it will be useful for someone.

Questions:
Answers:

You can do it in another way, you can add the delegate variable in Subclass and use it to access the SuperClassProtocol also using delegate?.foo().

protocol MySuperClassProtocol {
    func foo()
}

class MySuperClass {
    //var delegate:MySuperClassProtocol?
}

protocol MySubClassProtocol:MySuperClassProtocol {
    func bar()
}

class MySubClass: MySuperClass {
    var delegate:MySubClassProtocol?

    func test() {
        delegate?.foo()
        delegate?.bar()
    }
}

class UserClass:MySubClassProtocol {
    func foo() {
        println("foo!")
    }
    func bar() {
        println("bar")
    }
}

But the issue with this approach is you can never use MySuperClassProtocol independently unless you create a new SubClass of MySuperClass only for declaring delegate variable.