Search code examples
swiftcastingprotocols

How to call a protocol function from a non-conforming class?


I'm working with protocol and my app crashes when I try to call it from a class which doesn't conform to the protocol.

Playground code of the issue:

import Cocoa

var str = "Hello, playground"

public protocol example {
    func artihmetic(x: Int, y: Int) -> Int
}

class A : example {
    func artihmetic(x: Int, y: Int) -> Int { return x + y }
}

class B : example {
    func artihmetic(x: Int, y: Int) -> Int { return x * y }
}

class C {

    public init() {}

    func callArithmetic() {
        let x = 2, y = 2
        let z = (self as! example).artihmetic(x: x, y: y)
        print(z)
    }
}

let instC = C()
instC.callArithmetic()

This code crashes and I get this error:

Could not cast value of type '__lldb_expr_1.C' (0x112cd91c0) to '__lldb_expr_1.example' (0x7fff993f57e8)

I want to know if there is any alternate way or if it is possible to call a protocol function from a non-conforming class.


Solution

  • self as! example
    

    when you do that, the compiler will be like, "umm ok let me try that. Let's see the the type of self...ok. self is of type C. Is C a subclass of another type that conforms to example? No. Ok let me trying something else. Does the C class itself ever adopt the example protocol? No.! That's bad. I can't succeed. Oh shoot, they're using ! with as...I have to crash"

    C needs to adopt the example protocol. Are you doing that? No!

    Another more clear example is:

    protocol Feeder {
        func nurse()
    }
    
    class Human {
        func eat() {
            print("eat")
        }
    }
    
    class Man: Human{
    
    }
    
    class Woman: Human, Feeder {
        func nurse() {
            print("nurse baby")
        }
    }
    
    let human1: Human = Man()
    let human2: Human = Woman()
    
    func isFeeder(human: Human) {
        if let feeder = human as? Feeder { // very similar to: `self as! example`
            print("human is feeder!")
        } else {
            print("human is not feeder!")
        }
    }
    
    isFeeder(human: human1) // human is not feeder!
    isFeeder(human: human2) // human is feeder!