【问题标题】:Trying to call selector to static function in swift试图快速调用选择器到静态函数
【发布时间】:2018-11-27 15:00:45
【问题描述】:

我正在尝试实现以下目标,但遇到了问题:-)

  • 创建UIViewController和UIView子类可以采用的协议 其中包含一个要在此类上调用的静态方法(调用它 configuration
  • 然后我想使用 ObjectiveC 运行时来查找采用该协议的类
  • 在每个类上我都想调用configuration 方法
  • 配置方法是返回一个字典(key:描述字符串,value:类上要调用的选择器)

到目前为止,我能够创建协议,找到实现协议的类,但我遇到了编译问题。

这是协议

@objc public protocol MazeProtocol: NSObjectProtocol{
   @objc static func configurations() -> NSDictionary
}

这是在我的一个班级上采用该协议的扩展:

extension MapCoordinatorViewController: MazeProtocol {

static func configurations() -> NSDictionary {
    let returnValue = NSMutableDictionary()
    returnValue.setObject(#selector(test), forKey: "test" as NSString)
    return returnValue
}

@objc static func test() {

    print("test")
}}

这是我用来尝试调用从配置方法返回的选择器的代码:

let selectorKey = controllerClass.configurations().allKeys[indexPath.row]
let selector = controllerClass.configurations().object(forKey: selectorKey)
controllerClass.performSelector(selector)        <================ error here

ControllerClass 被声明为let controllerClass: MazeProtocol.Type

我收到以下编译警告: Instance member 'performSelector' cannot be used on type 'MazeProtocol'

我错过了什么?

【问题讨论】:

  • controllerClass.performSelector 是主要问题,MazeProtocol 的类型没有方法performSelector
  • 这是使用 Swift 语法的 Objective-C 代码。为什么不使用 Swift 特性编写这段代码呢?使用闭包代替选择器。使用 Swift 数据类型而不是 Objective-C 数据类型。

标签: swift swift-protocols objective-c-runtime


【解决方案1】:

你可以在技术上强制它工作。请不要。这是可怕的斯威夫特。为了让它发挥作用,你必须破坏 Swift 试图做的一切。但是,是的,通过警告,您可以在技术上让它编译和工作。请,请不要。

首先,您需要将selector 设为Selector。你正在使用NSDictionary,这在 Swift 中很糟糕,所以你得到了Any?。但是,是的,您可以as! 将其转换为您想要的:

let selector = controllerClass.configurations().object(forKey: selectorKey) as! Selector

然后,不顾所有类型之神,您可以声明类实际上是NSObjectProtocol,因为为什么不呢?

(controllerClass as! NSObjectProtocol).perform(selector)

这将引发警告“从 'MapCoordinatorViewController.Type' 转换为不相关类型 'NSObjectProtocol' 总是失败”,但实际上它会成功。

毕竟“不要这样做”,你应该怎么做?带闭包。

public protocol MazeProtocol {
    static var configurations: [String: () -> Void] { get }
}

class MapCoordinatorViewController: UIViewController {}

extension MapCoordinatorViewController: MazeProtocol {

    static let configurations: [String: () -> Void] = [
        "test": test
    ]
    static func test() {
        print("test")
    }
}


let controllerClass = MapCoordinatorViewController.self
let method = controllerClass.configurations["test"]!
method()

【讨论】:

  • 谢谢 Rob,我对协议部分太投入了,以至于我没有想到一个快速的解决方案。
  • 我刚试过这个。我的问题是我正在使用objectiveC 运行时来查找哪个类正在采用MazeProtocol。所以 MazeProtocol 需要是一个 @objc 协议 :-( 所以这不起作用,因为 [String: () -> Void] “不能在 ObjectiveC 中表示”。还有其他想法吗?
  • 您必须将其设为[String: String] 并将选择器来回转换为字符串(NSStringFromSelector、NSSelectorFromString)。但是,我通常不推荐这种自动发现。我建议有一个明确的步骤来注册你的课程。它通常是应用程序委托中的一行代码,它消除了各种神奇和微妙的错误。
  • 谢谢,我会考虑改用注册方法。感谢您的帮助
猜你喜欢
  • 2015-06-30
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2016-11-16
  • 1970-01-01
  • 2016-06-02
  • 2020-06-05
  • 1970-01-01
相关资源
最近更新 更多