尝试快速将选择器调用为静态函数

时间:2018-11-27 15:00:45

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

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

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

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

这是协议

@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'

我想念什么?

1 个答案:

答案 0 :(得分:4)

从技术上讲,您可以强制执行此操作。请不要这太可怕了。为了使它起作用,您必须破坏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()