【问题标题】:Checking if a Swift class conforms to a protocol and implements an optional function?检查 Swift 类是否符合协议并实现可选功能?
【发布时间】:2016-04-07 11:29:07
【问题描述】:

我正在用 Swift 编写一个用于 SpriteKit 游戏的辅助函数,它将检查碰撞滞留是否已正确设置。

我想检查我的 GameScene 是否实现了协议 SKPhysicsContactDeletegate 并且还包含 didBeginContact 函数。

我有以下代码,是在 Xcode 的自动完成功能的帮助下编写的:

    if GameScene(conformsToProtocol(SKPhysicsContactDelegate)) {
        if GameScene(respondsToSelector(didBeginContact(SKPhysicsContact))) {
            print("Self implements SKPhysicsContactDelegate and didBeginContact appears to be present")
        }
    }

Xcode 然后抱怨我的conformsToProtocol,抱怨

'参数标签'(_:)' 不匹配任何可用的重载'

没有建议如何解决。它还反对respondsToSelector,指出

'无法转换类型'(SKPhysicsContact).Type'的值(又名 'SKPhysicsContact.Type')到预期的参数类型'SKPhysicsContact'

如何检查我的 GameScene 是否符合此协议并实现此功能?

编辑:这是我根据答案编写的代码:

if GameScene.self is SKPhysicsContactDelegate {
    print("Yes it's a delegate")
}

输出:Yes it's a delegate

let yy = (GameScene.self as? SKPhysicsContactDelegate)?.didBeginContact
print("yy is \(yy)")

输出:yy is nil

if (GameScene.self as? SKPhysicsContactDelegate)?.didBeginContact != nil {
    print("Yes it's a delegate and the function is there")
}

没有输出。

【问题讨论】:

  • 尝试用实际变量替换GameScene.self
  • @redent84 - 成功了 - 谢谢。现在只需要检查physicsWorld.contactDelegate 是否设置为'self'。
  • 我已经扩展了我的答案以解释 GameScene.self 场景

标签: swift


【解决方案1】:

你还在用 Objective-C 思考,拥抱 Swift!

假设您的协议如下所示:

@objc protocol SKPhysicsContactDelegate {
    optional func didBeginContact()
}

试试这个:

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

或者一个班轮:

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

注意到调用中方法名称后面的? 了吗?这是因为该方法是可选的,如果对象没有实现该方法,它将不会被调用。如果对象不符合SKPhysicsContactDeletegate 协议,if let 分支将不会被执行。


不调用就检查方法是否存在

要在调用之前检查方法本身是否存在,只需省略方法调用以获取对该方法的引用并像检查任何其他变量一样检查它:

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

如果您以后不需要调用它,只需检查nil

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

检查静态方法

检查optional static 方法使用相同的方法,但需要类对象而不是类的实例:

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

注意GameScene.self 获取对象类型和<protocol>.Type 转换为协议类而不是协议实例。


完整样本

附上 Playgrounds、Swift script 或任何 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'

【讨论】:

  • 这让我想知道如何检查一个对象是否实现了一个方法而不试图调用它?例如。可选方法采用创建成本高昂的参数,因此您需要在准备参数并进行调用之前检查该方法是否已实现。
  • 但是我不想调用这个函数,只检查它是否存在......(即他所说的)你不要直接调用didBeginContact;它被称为 SpriteKit 游戏循环的一部分。
  • @redent84 - 那么您上次编辑时发生了什么?我可以看到您检查了 GameScene 是否实现了该协议,但是如果 .didBegincontact 存在,它不会实际调用该函数,或者是否正在发生一些事情只是检查该函数是否存在?
  • didBeginContact 将获得对该方法的引用。然后,您可以检查引用是否不是 nil 以检查它是否存在。该方法未被调用。
  • OK - 刚刚通过在 func test() 上尝试验证了这一点,并得到“SKPhysicsContactDelegate 不包含测试”(或类似的词)。但是,这不是触发,因为它仍然返回 nil。
【解决方案2】:

respondsToSelector 失败,因为它需要一个 SKPhysicsContact 实例而不是 SKPhysicsContact.type。

要检查一个对象是否实现了一个接口,你可以使用is。 比如:

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

【讨论】:

  • 这适用于:如果 GameScene.self 是 SKPhysicsContactDelegate {
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
相关资源
最近更新 更多