Protocol Extensions and subclasses - ios

I am wondering why the following doesn't print out what I think it should.
/* Fails */
protocol TheProtocol {
func update()
}
class A: TheProtocol {
}
class B : A {}
extension TheProtocol {
func update() {
print("Called update from TheProtocol")
}
}
extension TheProtocol where Self: B {
func update() {
print("Called update from B")
}
}
let instanceB = B()
instanceB.update()
let instanceBViaProtocol:TheProtocol = B()
instanceBViaProtocol.update()
This will print the following:
Called update from B
Called update from TheProtocol // Why not: Called update from B (extension)
I am especially wondering why
instanceBViaProtocol.update()
Doesn't execute the update() in the extension on TheProtocol:
extension TheProtocol where Self: B {
func update() {
print("Called update from B")
}
}
I would think it would since B inherits from A which adopts TheProtocol, so I would think that B would then implicitly adopt TheProtocol as well.
Moving the protocol adoption to B from A yields the expected result.
protocol TheProtocol {
func update()
}
class A { // Remove TheProtocol
}
class B : A, TheProtocol {} // Add TheProtocol
extension TheProtocol {
func update() {
print("Called update from TheProtocol")
}
}
extension TheProtocol where Self: B {
func update() {
print("Called update from B")
}
}
let instanceB = B()
instanceB.update()
let instanceBViaProtocol:TheProtocol = B()
instanceBViaProtocol.update()
Result:
Called update from B
Called update from B
I took a look at https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94#.6cm4oqaq1 and http://krakendev.io/blog/subclassing-can-suck-and-heres-why, but I was unable to figure this out. Are extension methods not honored on subclasses of entities that adopt the protocol?

The answer is Method Dispatch + a Bug in Swift.
Method dispatch is the mechanism used by the compiler to choose an implementation to execute when a method is invoked. Swift uses 3 kinds of method dispatch. You can read about it here
The dispatch method, is determined by the type of the reference, not by the type of the instance. In your case the reference type is TheProtocol.
let instanceBViaProtocol:TheProtocol = B()
instanceBViaProtocol.update()
You have a protocol extension that defines common behavior for a requirement method. In that case, dynamic dispatch is used. That means that the implementation declared in B should be used. But there is a bug in Swift that causes the issue.
For each type Swift uses a witness table to register the implementations used for dynamic dispatch. The bug causes the B class to fail to register its implementation of update() in the Witness table of TheProtocol. And when update is dispatched through the TheProtocol table, the wrong implementation is used.
Here you have your example with some changes. Notice that if you declare update in the superclass and override it in the subclass, it works as expected. That's the clearest way to see the bug to mee.
protocol TheProtocol {
func update()
}
class A: TheProtocol {
func update(){
print("Implementation of A")
}
}
class B : A {
override func update(){
print("Implementation of B")
}
}
//All those who conform to TheProtocol will execute this.
extension TheProtocol {
func update() {
print("Common: TheProtocol")
}
}
extension TheProtocol where Self: B {
func update() {
print("Common: TheProtocol for B's")
}
}
extension TheProtocol where Self: A {
func update() {
print("Common: TheProtocol for A's")
}
}
let instanceBViaProtocol:TheProtocol = B() //It prints "Implementation of B"
instanceBViaProtocol.update()
I hope this answers you question.
https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/ has an awesome explanation on method dispatch in swift.
Here you can read a short thing I wrote about method dispatch in protocol extensions.

Related

Unable to call another class method using delegate in swift

I'm trying to call method of Class B from class A on the button tap event. But it does not work and below is my code.
// Viewcontroller
class ViewController: UIViewController {
#IBAction func btnClicked(_ sender: Any) {
var objA = A()
objA.delegate?.TestA()
}
}
// ClassA.swift
protocol TestA {
func TestA()
}
class A {
var delegate: TestA?
}
// ClassB.swift
class B : TestA {
func TestA() {
print(" Function A from b")
}
}
When tapping a button, function TestA() does not invoke.
I even tried the code below, but it also didn't work:
var objB = B()
var objA = A()
objA.delegate = objB
Because you instantiate instance of Class A using
var objA = A()
Clearly you haven't initialised delegate property in A because its optional its default value is nil
Now when you call
objA.delegate?.TestA()
delegate is nil hence function TestA will not be called
Suggestion
Always use camelCasing for declaring names of functions. So TestA() is incorrect rather use testA()
EDIT 1:
Tested this
#IBAction func btnClicked(_ sender: Any) {
let objA = A()
let objB = B()
objA.delegate = objB
objA.delegate?.TestA()
}
This is working fine what is the issue?
The objA.delegate is never assigned to an object, so it has an initial value of nil. The ? operator avoids calling a function on a nil object.
The answer by Sandeep Bhandari is right.
Some information for better understanding of Protocol and Delegates.
TestA is a protocol and an optional var delegate is defined in class A. This setup is right. The idea behind this setup is that any user of class A, in this case class B which conforms to protocol TestA gets a callback from class A. You need to call the delegate.testA() function from within class A.
The current implementation of ViewController is not at all benefiting from defining Protocol and Delegates.
To achieve proper usage, the class A cab be modified as follows:
protocol TestA {
func testA()
}
class A {
var delegate: TestA?
func process() {
// Do something and call delegate function to report it.
delegate?.testA()
}
}
And modify ViewController as follows (copied class B for completeness):
class ViewController: UIViewController {
#IBAction func btnClicked(_ sender: Any) {
var objA = A()
var objB = B()
objA.delegate = objB
objA.process()
}
}
// ClassB.swift
class B : TestA {
func TestA() {
print(" Function A from b")
}
}
Now function implemented in class B to conform to protocol TestA will be called when process() function on objA of class A is called.
This is better use of Protocol and Delegate. Hope this helps.

In Swift protocols - Why am I being forced to use the keyword 'Final' before my Sheep class? [duplicate]

I have a protocol P that returns a copy of the object:
protocol P {
func copy() -> Self
}
and a class C that implements P:
class C : P {
func copy() -> Self {
return C()
}
}
However, whether I put the return value as Self I get the following error:
Cannot convert return expression of type 'C' to return type 'Self'
I also tried returning C.
class C : P {
func copy() -> C {
return C()
}
}
That resulted in the following error:
Method 'copy()' in non-final class 'C' must return Self to conform
to protocol 'P'
Nothing works except for the case where I prefix class C with final ie do:
final class C : P {
func copy() -> C {
return C()
}
}
However if I want to subclass C then nothing would work. Is there any way around this?
The problem is that you're making a promise that the compiler can't prove you'll keep.
So you created this promise: Calling copy() will return its own type, fully initialized.
But then you implemented copy() this way:
func copy() -> Self {
return C()
}
Now I'm a subclass that doesn't override copy(). And I return a C, not a fully-initialized Self (which I promised). So that's no good. How about:
func copy() -> Self {
return Self()
}
Well, that won't compile, but even if it did, it'd be no good. The subclass may have no trivial constructor, so D() might not even be legal. (Though see below.)
OK, well how about:
func copy() -> C {
return C()
}
Yes, but that doesn't return Self. It returns C. You're still not keeping your promise.
"But ObjC can do it!" Well, sort of. Mostly because it doesn't care if you keep your promise the way Swift does. If you fail to implement copyWithZone: in the subclass, you may fail to fully initialize your object. The compiler won't even warn you that you've done that.
"But most everything in ObjC can be translated to Swift, and ObjC has NSCopying." Yes it does, and here's how it's defined:
func copy() -> AnyObject!
So you can do the same (there's no reason for the ! here):
protocol Copyable {
func copy() -> AnyObject
}
That says "I'm not promising anything about what you get back." You could also say:
protocol Copyable {
func copy() -> Copyable
}
That's a promise you can make.
But we can think about C++ for a little while and remember that there's a promise we can make. We can promise that we and all our subclasses will implement specific kinds of initializers, and Swift will enforce that (and so can prove we're telling the truth):
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
// Perform your copying here.
}
}
And that is how you should perform copies.
We can take this one step further, but it uses dynamicType, and I haven't tested it extensively to make sure that is always what we want, but it should be correct:
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
// Perform your copying here.
}
}
Here we promise that there is an initializer that performs copies for us, and then we can at runtime determine which one to call, giving us the method syntax you were looking for.
With Swift 2, we can use protocol extensions for this.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
There is another way to do what you want that involves taking advantage of Swift's associated type. Here's a simple example:
public protocol Creatable {
associatedtype ObjectType = Self
static func create() -> ObjectType
}
class MyClass {
// Your class stuff here
}
extension MyClass: Creatable {
// Define the protocol function to return class type
static func create() -> MyClass {
// Create an instance of your class however you want
return MyClass()
}
}
let obj = MyClass.create()
Actually, there is a trick that allows to easily return Self when required by a protocol (gist):
/// Cast the argument to the infered function return type.
func autocast<T>(some: Any) -> T? {
return some as? T
}
protocol Foo {
static func foo() -> Self
}
class Vehicle: Foo {
class func foo() -> Self {
return autocast(Vehicle())!
}
}
class Tractor: Vehicle {
override class func foo() -> Self {
return autocast(Tractor())!
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
let vehicle = Vehicle.foo()
let tractor = Tractor.foo()
print(typeName(vehicle)) // Vehicle
print(typeName(tractor)) // Tractor
Swift 5.1 now allow a forced cast to Self, as! Self
1> protocol P {
2. func id() -> Self
3. }
9> class D : P {
10. func id() -> Self {
11. return D()
12. }
13. }
error: repl.swift:11:16: error: cannot convert return expression of type 'D' to return type 'Self'
return D()
^~~
as! Self
9> class D : P {
10. func id() -> Self {
11. return D() as! Self
12. }
13. } //works
Following on Rob's suggestion, this could be made more generic with associated types. I've changed the example a bit to demonstrate the benefits of the approach.
protocol Copyable: NSCopying {
associatedtype Prototype
init(copy: Prototype)
init(deepCopy: Prototype)
}
class C : Copyable {
typealias Prototype = C // <-- requires adding this line to classes
required init(copy: Prototype) {
// Perform your copying here.
}
required init(deepCopy: Prototype) {
// Perform your deep copying here.
}
#objc func copyWithZone(zone: NSZone) -> AnyObject {
return Prototype(copy: self)
}
}
I had a similar problem and came up with something that may be useful so I though i'd share it for future reference because this is one of the first places I found when searching for a solution.
As stated above, the problem is the ambiguity of the return type for the copy() function. This can be illustrated very clearly by separating the copy() -> C and copy() -> P functions:
So, assuming you define the protocol and class as follows:
protocol P
{
func copy() -> P
}
class C:P
{
func doCopy() -> C { return C() }
func copy() -> C { return doCopy() }
func copy() -> P { return doCopy() }
}
This compiles and produces the expected results when the type of the return value is explicit. Any time the compiler has to decide what the return type should be (on its own), it will find the situation ambiguous and fail for all concrete classes that implement the P protocol.
For example:
var aC:C = C() // aC is of type C
var aP:P = aC // aP is of type P (contains an instance of C)
var bC:C // this to test assignment to a C type variable
var bP:P // " " " P " "
bC = aC.copy() // OK copy()->C is used
bP = aC.copy() // Ambiguous.
// compiler could use either functions
bP = (aC as P).copy() // but this resolves the ambiguity.
bC = aP.copy() // Fails, obvious type incompatibility
bP = aP.copy() // OK copy()->P is used
In conclusion, this would work in situations where you're either, not using the base class's copy() function or you always have explicit type context.
I found that using the same function name as the concrete class made for unwieldy code everywhere, so I ended up using a different name for the protocol's copy() function.
The end result is more like:
protocol P
{
func copyAsP() -> P
}
class C:P
{
func copy() -> C
{
// there usually is a lot more code around here...
return C()
}
func copyAsP() -> P { return copy() }
}
Of course my context and functions are completely different but in spirit of the question, I tried to stay as close to the example given as possible.
Just throwing my hat into the ring here. We needed a protocol that returned an optional of the type the protocol was applied on. We also wanted the override to explicitly return the type, not just Self.
The trick is rather than using 'Self' as the return type, you instead define an associated type which you set equal to Self, then use that associated type.
Here's the old way, using Self...
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
Here's the new way using the associated type. Note the return type is explicit now, not 'Self'.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
To add to the answers with the associatedtype way, I suggest to move the creating of the instance to a default implementation of the protocol extension. In that way the conforming classes won't have to implement it, thus sparing us from code duplication:
protocol Initializable {
init()
}
protocol Creatable: Initializable {
associatedtype Object: Initializable = Self
static func newInstance() -> Object
}
extension Creatable {
static func newInstance() -> Object {
return Object()
}
}
class MyClass: Creatable {
required init() {}
}
class MyOtherClass: Creatable {
required init() {}
}
// Any class (struct, etc.) conforming to Creatable
// can create new instances without having to implement newInstance()
let instance1 = MyClass.newInstance()
let instance2 = MyOtherClass.newInstance()

Swift protocol extension method dispatch with superclass and subclass

I found an interesting behaviour which seems like a bug...
Based on the behaviour described the following articles:
https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94
http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
The output is not what I expect, when I add SomeSuperclass, rather than directly adopting the protocol.
protocol TheProtocol {
func method1()
}
extension TheProtocol {
func method1() {
print("Called method1 from protocol extension")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from protocol extension")
}
}
// This is the difference - adding a superclass
class SomeSuperclass: TheProtocol {
}
// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol
class MyClass: SomeSuperclass {
func method1() {
print("Called method1 from MyClass implementation")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
let foo: TheProtocol = MyClass()
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension"
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension
Do you know if this is a bug, or by design? A colleague suggested perhaps mixing inheritance and protocol extensions might not work as expected. I was intending to use the protocol extension to provide a default implementation... if I can't do it, then I will sadly have to mark it #objc and go back to an optional protocol.
From the post The Ghost of Swift Bugs Future, here are the rules for dispatch for protocol extensions that are mentioned at the end of the post.
IF the inferred type of a variable is the protocol:
AND the method is defined in the original protocol THEN the
runtime type’s implementation is called, irrespective of whether
there is a default implementation in the extension.
AND the method is not defined in the original protocol, THEN the
default implementation is called.
ELSE IF the inferred type of the variable is the type THEN the type’s implementation is called.
So in your condition, you're saying that method1() is defined in the protocol and it has been implemented in the subclass. But your superclass is adopting the protocol but it is not implementing the method1() and subclass just inherits from the Superclass and doesn't adopt to the protocols directly. That's why I believe that is the reason when you call foo.method1(), it doesn't invoke the the subclass implementation as stated by point 1 & 2.
But when you do,
class SomeSuperclass: TheProtocol {
func method1(){
print("super class implementation of method1()")}
}
class MyClass : SomeSuperclass {
override func method1() {
print("Called method1 from MyClass implementation")
}
override func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
and then when you call,
let foo: TheProtocol = MyClass()
foo.method1() // Called method1 from MyClass implementation
foo.method2NotInProtocol()
So what could be the workaround for this bug (which seems to be a bug) is that, you need to implement the protocol method in the superclass and then you need to override the protocol method in the sub class. HTH
Please check the code below:
import UIKit
protocol TheProtocol {
func method1()
func method2NotInProtocol()
}
extension NSObject {
func method1() {
print("Called method1 from protocol extension")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from protocol extension")
}
}
// This is the difference - adding a superclass
class SomeSuperclass :NSObject, TheProtocol {
override func method1() {
print("Called method1 from SomeSuperclass implementation")
}
}
// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol
class MyClass : SomeSuperclass {
override func method1() {
print("Called method1 from MyClass implementation")
}
override func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
let foo: TheProtocol = MyClass()
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension"
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension
Instead of writing extension to TheProtocol, write extension to a abstract class(NSObject in above code). This works as expected.
An option that hasn't been considered is to split up your protocol into several smaller ones, such that the superclass does not need to conform to protocols containing methods it does not intend to implement. The subclass can then subscribe to these other protocols separately.

Extension doesn't go in derived class in swift [duplicate]

This question already has answers here:
Swift 2 protocol extension not calling overridden method correctly
(3 answers)
Closed 7 years ago.
I am implementing a protocol and providing some optional methods in swift but then I am implement these optional methods in derived class. When I call a protocol method it is calling extension method not the derived class method.
protocol ProtocolA {
func method1()
// Optional
func method2()
}
extension ProtocolA {
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Protocol A")
}
}
class A : ProtocolA {
func method1() {
print("In method 1 - class A")
}
}
class B : A {
func method2() {
print("In method 2 - Class B")
}
}
var a : A = B()
// It should call - In method 2 - Class B but the output is "In method 2 - Protocol A"
a.method2()
First you should implement the method on Class A for on class B you can override the method for example:
protocol ProtocolA {
func method1()
// Optional
func method2()
}
extension ProtocolA {
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Protocol A")
}
}
class A : ProtocolA {
func method1() {
print("In method 1 - Class A")
}
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Class A")
}
}
class B : A {
override func method2() {
print("In method 2 - Class B")
}
}
var a : A = B()
a.method2()
or use the class B as a Type directly:
protocol ProtocolA {
func method1()
// Optional
func method2()
}
extension ProtocolA {
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Protocol A")
}
}
class A : ProtocolA {
func method1() {
print("In method 1 - Class A")
}
// func method2(){
// // It comes here, instead of class B method2.
// print("In method 2 - Class A")
// }
}
class B : A {
func method2() {
print("In method 2 - Class B")
}
}
var b : B = B()
b.method2()
The problem is the runtime choose the function that was implemented based on the Type of variable.

Protocol extension method dispatch in Swift 2.0

I'm facing a problem regarding protocols methods dispatch.
I have a class hierarchy that looks like that:
protocol E {
func test()
}
extension E {
func test() {
print("jello")
}
}
class A: E {
}
class B: A {
func test() {
print("hello")
}
}
But when I call test on an instance of class B statically forced to be typed A, "jello" gets printed, not "hello".
let b: A = B() // prints "jello" not "hello"
b.test()
My understanding is that test method printing "jello" gets "integrated" into instances of A (since A conforms to E protocol). I'm then providing another implementation of test inside B (that inherits form A). I thought polymorphism would work here and calling test on B instance that are stored inside A references would print hello. What's happening here?
It's perfectly working when not using any protocol:
class A {
func test() {
print("jello")
}
}
class B: A {
override func test() {
print("hello")
}
}
let b: A = B() // prints "hello"
b.test()
What's different from adopting a protocol that adds new methods to my parent class and providing a new implementation in a subclass, than having directly written this method in the parent class and then overriding it in a subclass?
Do you guys have any workaround?
Smells like a bug.
The only workaround I came up with was very ugly...
protocol E {
func test()
}
func E_test(_s: E) {
print("jello")
}
extension E {
func test() { E_test(self) }
}
class A: E {
func test() { E_test(self) }
}
class B: A {
override func test() {
print("hello")
}
}
let b: A = B()
b.test()
It is a bug indeed. Here is the link to it: https://bugs.swift.org/browse/SR-103

Resources