【问题标题】:Is there a typesafe way to use selectors in Swift?在 Swift 中是否有一种类型安全的方式来使用选择器?
【发布时间】:2014-06-09 14:42:38
【问题描述】:

在大多数情况下,就类型安全而言,Swift 比 Objective-C 有了巨大的改进。一个明显的例外是选择器。在 Objective-C 中,使用表达式 @selector(notARealSelector:) 将给出编译器警告。 Swift 等效项Selector("notARealSelector:") 将始终编译,但在运行时会失败。

在 Swift 中是否有一种类型安全的方式来使用选择器,以便我可以使用需要它们的 Objective-C API?

我的应用中有很多 NSNotification 观察者,并且希望在编译时检查我没有在我的选择器中打错字。

编辑:具体用例为NSNotificationCenter.addObserver

【问题讨论】:

  • 您能举例说明您目前如何使用@selector() 块吗?您调用这些方法的对象是否随时公开(通过协议一致性或子类化)这些方法?您可以使用myDelegate?.scrollViewDidScroll?(...),但这要求委托至少符合协议,以便编译器有机会确定该方法是否可能存在。
  • 就像我在问题中所说的,NSNotificationCenter.addObserver
  • @selector 的另一个常见用途是UIControl 和子类使用的目标/动作。例如button.addTarget(self, action: "doTap", forControlEvents: .TouchUpInside) - 令人沮丧的是,由于拼写错误或方法名称更改,快速编译器无法警告错误。
  • 不是对您关于使用 swift 选择器的一般类型安全的问题的具体答案,但如果您想在这种特定情况下保持类型安全,则此通知调用的一个版本改为使用块选择器的:public func addObserverForName(name: String?, object obj: AnyObject?, queue: NSOperationQueue?, usingBlock block: (NSNotification) -> Void) -> NSObjectProtocol。见codefellows.org/blog/…

标签: selector swift type-safety


【解决方案1】:

Typesafe 选择器刚刚在 Xcode 7.3 beta 4 中发布:

let sel = #selector(insertSubview(_:aboveSubview:)) // sel has type

Selector 现在是一等公民,并带有一些不错的 Swift 编译器警告。如果需要,您仍然可以传入一个字符串:

let sel = Selector("propertyName")

在此处查看更完整的答案:@selector() in Swift?

Xcode 发行说明:http://adcdownload.apple.com/Developer_Tools/Xcode_7.3_beta_4/Xcode_7.3_beta_4_Release_Notes.pdf

【讨论】:

  • @Bill 也可以在这里查看我的讨论:stackoverflow.com/a/35658335/341994 这彻底解释了新的#selector 语法。自从你(正确地)提出你的问题来提出这个问题以来,他们只花了两年时间...... :) 在我看来,类型安全中的这个漏洞一直以来都是所有这些的巨大矛盾斯威夫特应该代表。现在这个坑已经被填满了。
【解决方案2】:

使用 Swift 的 optionals 概念:

if let result = object.notARealSelector?(/* args */) {
   // Use Result
}

object 的类型上没有定义这样的方法时,?notARealSelector 之后使用并返回falseif

optional protocol requirements 有一个警告:

仅当您的协议被标记时,才能指定可选协议要求 带有@objc 属性。即使您不与 Objective-C 互操作, 如果要指定,则需要使用 @objc 属性标记您的协议 可选要求。

但由于您首先询问的是可选方法,因此您必须在 Objective-C 上下文中讨论这个问题。

【讨论】:

  • 是的,正如我在问题中所说,我正在尝试将选择器传递给NSNotificationCenter
  • 此外,将函数视为可选仅适用于可选协议方法 - 你不能这样做 object.notARealSelector 除非 object 是协议类型的变量/常量并且所述协议是 @987654330将notARealSelector 声明为@optional 方法的@ 协议。
【解决方案3】:

您可以使用反射将对象属性的名称作为字符串获取,如 this answer 中总结的那样,但这不会像 @selector 在 ObjC 中那样建立标识符与其字符串名称之间的连接。一些创造性地使用反射可能会解决这个问题,但你也可以通过file a bug 做得很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 2013-04-21
    相关资源
    最近更新 更多