Checking if a Swift class conforms to a protocol and implements an optional function?

后端 未结 2 1436
青春惊慌失措
青春惊慌失措 2021-02-07 06:46

I\'m writing a helper function in Swift for use in SpriteKit games that will check if the collision detention has been set up correctly.

I want to check that my GameScen

相关标签:
2条回答
  • 2021-02-07 07:03

    respondsToSelector fails, because it expects an instance of SKPhysicsContact and not SKPhysicsContact.type.

    To check if an object implements an interface, you can use is. So for example:

    protocol Test {
        func foo();
    }
    
    class TestImpl : Test {
        func foo() {
            print("bar")
        }
    }
    
    let a = TestImpl()
    let b = String()
    print(a is Test) // true
    print(b is Test) // false
    
    0 讨论(0)
  • 2021-02-07 07:14

    You are still thinking in Objective-C, embrace Swift!

    Assuming that your protocol looks like this:

    @objc protocol SKPhysicsContactDelegate {
        optional func didBeginContact()
    }
    

    Try this:

    if let delegate = gameScene as? SKPhysicsContactDelegate {
        delegate.didBeginContact?()
    }
    

    Or a one liner:

    (gameScene as? SKPhysicsContactDelegate)?.didBeginContact?()
    

    Notice the ? after the method name in the call? It's because that method is optional and it won't get called if the object doesn't implement that method. And the if let branch won't get executed if the object doesn't conforms to SKPhysicsContactDeletegate protocol.


    Check method existence without call

    To check the existence of the method itself before calling, just omit the method call to get a reference to that methodand check it like any other variable:

    if let method = (gameScene as? SKPhysicsContactDelegate)?.didBeginContact {
        print("gameScene conforms to SKPhysicsContactDelegate and implements didBeginContact")
        // Call it later whenever you want
        method()
    }
    

    If you don't need to call it later, just check for nil:

    if (gameScene as? SKPhysicsContactDelegate)?.didBeginContact != nil {
        print("gameScene conforms to SKPhysicsContactDelegate and implements didBeginContact")
    }
    

    Check for static methods

    Checking for optional static methods uses the same approach, but requires the class object instead of an instance of the class:

    if (GameScene.self as? OptionalProtocol.Type)?.staticMethod != nil {
        print("gameScene conforms to OptionalProtocol and implements staticMethod")
    }
    

    Notice GameScene.self for obtaining the object type and <protocol>.Type to cast to the protocol class instead of a protocol instance.


    Full sample

    Attached full sample for Playgrounds, Swift script or any online Swift compiler:

    import Foundation
    
    @objc protocol OptionalProtocol {
        optional func instanceMethod()
        optional static func staticMethod()
    }
    
    class Nothing {}
    class Something: OptionalProtocol {}
    class Bar: NSObject, OptionalProtocol {
        func instanceMethod() {
            print("Instance method")
        }
    }
    class Foo: NSObject, OptionalProtocol {
        static func staticMethod() {
            print("Static method")
        }
    }
    
    // Cast instances to 'Any' and classes to 'AnyClass'
    let nothing: Any = Nothing()
    let nothingClass: AnyClass = Nothing.self
    let something: Any = Something()
    let somethingClass: AnyClass = Something.self
    let bar: Any = Bar()
    let barClass: AnyClass = Bar.self
    let foo: Any = Foo()
    let fooClass: AnyClass = Foo.self
    
    nothing is OptionalProtocol // false
    (nothing as? OptionalProtocol)?.instanceMethod != nil // false
    (nothing as? OptionalProtocol)?.instanceMethod?() // Does nothing
    (nothingClass as? OptionalProtocol.Type)?.staticMethod != nil // false
    (nothingClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Does nothing
    
    something is OptionalProtocol // true
    (something as? OptionalProtocol)?.instanceMethod != nil // false
    (something as? OptionalProtocol)?.instanceMethod?() // Does nothing
    (somethingClass as? OptionalProtocol.Type)?.staticMethod != nil // false
    (somethingClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Does nothing
    
    bar is OptionalProtocol // true
    (bar as? OptionalProtocol)?.instanceMethod != nil // true
    (bar as? OptionalProtocol)?.instanceMethod?() // Prints 'Instance method'
    (barClass as? OptionalProtocol.Type)?.staticMethod != nil // false
    (barClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Does nothing
    
    foo is OptionalProtocol // true
    (foo as? OptionalProtocol)?.instanceMethod != nil // false
    (foo as? OptionalProtocol)?.instanceMethod?() // Does nothing
    (fooClass as? OptionalProtocol.Type)?.staticMethod != nil // true
    (fooClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Prints 'Static method'
    
    0 讨论(0)
提交回复
热议问题