Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
383 views
in Technique[技术] by (71.8m points)

swift2 - Swift 2 protocol extension not calling overridden method correctly

I've been running into an issue using Swift 2's protocol extensions with default implementations. The basic gist is that I've provided a default implementation of a protocol method which I am overriding in a class that implements the protocol. That protocol extension method is being called from a base class, which is then calling a method which I have overridden in a derived class. The result is that the overridden method is not being called.

I've tried to distill the problem to the smallest possible playground which illustrates the issue below.

protocol CommonTrait: class {
    func commonBehavior() -> String
}

extension CommonTrait {
    func commonBehavior() -> String {
        return "from protocol extension"
    }
}

class CommonThing {
    func say() -> String {
        return "override this"
    }
}

class ParentClass: CommonThing, CommonTrait {
    override func say() -> String {
        return commonBehavior()
    }
}

class AnotherParentClass: CommonThing, CommonTrait {
    override func say() -> String {
        return commonBehavior()
    }
}

class ChildClass: ParentClass {
    override func say() -> String {
        return super.say()
        // it works if it calls `commonBehavior` here and not call `super.say()`, but I don't want to do that as there are things in the base class I don't want to have to duplicate here.
    }
    func commonBehavior() -> String {
        return "from child class"
    }
}

let child = ChildClass()
child.say() // want to see "from child class" but it's "from protocol extension”
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Unfortunately protocols don't have such an dynamic behavior (yet).

But you can do that (with the help of classes) by implementing commonBehavior() in the ParentClass and overriding it in the ChildClass. You also need CommonThing or another class to conform to CommonTrait which is then the superclass of ParentClass:

class CommonThing: CommonTrait {
    func say() -> String {
        return "override this"
    }
}

class ParentClass: CommonThing {
    func commonBehavior() -> String {
        // calling the protocol extension indirectly from the superclass
        return (self as CommonThing).commonBehavior()
    }

    override func say() -> String {
        // if called from ChildClass the overridden function gets called instead
        return commonBehavior()
    }
}

class AnotherParentClass: CommonThing {
    override func say() -> String {
        return commonBehavior()
    }
}

class ChildClass: ParentClass {
    override func say() -> String {
        return super.say()
    }

    // explicitly override the function
    override func commonBehavior() -> String {
        return "from child class"
    }
}
let parent = ParentClass()
parentClass.say()          // "from protocol extension"
let child = ChildClass()
child.say()                // "from child class"

Since this is only a short solution for your problem I hope it fits in your project.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...