简体   繁体   中英

Protocol inheritance + delegates in Swift

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".

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM