@selector() 在 Swift 中? [英] @selector() in Swift?

查看:63
本文介绍了@selector() 在 Swift 中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Swift 中创建一个 NSTimer 但我遇到了一些问题.

I'm trying to create an NSTimer in Swift but I'm having some trouble.

NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)

test() 是同一个类中的函数.

test() is a function in the same class.

我在编辑器中出现错误:

I get an error in the editor:

找不到接受提供的init"的重载论据

Could not find an overload for 'init' that accepts the supplied arguments

当我将 selector: test() 更改为 selector: nil 时,错误消失了.

When I change selector: test() to selector: nil the error disappears.

我试过了:

  • 选择器:test()
  • 选择器:测试
  • selector: Selector(test())

但没有任何效果,我在参考资料中找不到解决方案.

But nothing works and I can't find a solution in the references.

推荐答案

Swift 本身 不使用选择器——Objective-C 中使用选择器的几种设计模式在 Swift 中的工作方式有所不同.(例如,在协议类型上使用可选链或 is/as 测试而不是 respondsToSelector:,并尽可能使用闭包而不是 performSelector: 为了更好的类型/内存安全.)

Swift itself doesn't use selectors — several design patterns that in Objective-C make use of selectors work differently in Swift. (For example, use optional chaining on protocol types or is/as tests instead of respondsToSelector:, and use closures wherever you can instead of performSelector: for better type/memory safety.)

但是仍然有许多重要的基于 ObjC 的 API 使用选择器,包括计时器和目标/动作模式.Swift 提供了 Selector 类型来处理这些.(Swift 自动使用它来代替 ObjC 的 SEL 类型.)

But there are still a number of important ObjC-based APIs that use selectors, including timers and the target/action pattern. Swift provides the Selector type for working with these. (Swift automatically uses this in place of ObjC's SEL type.)

您可以使用 #selector 表达式从 Swift 函数类型构造一个 Selector.

You can construct a Selector from a Swift function type using the #selector expression.

let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)

这种方法的优点是什么?Swift 编译器会检查函数引用,因此您只能将 #selector 表达式用于实际存在且可用作选择器的类/方法对(请参阅下面的选择器可用性").您也可以根据 Swift 2.2+ 函数类型命名规则.

The great thing about this approach? A function reference is checked by the Swift compiler, so you can use the #selector expression only with class/method pairs that actually exist and are eligible for use as selectors (see "Selector availability" below). You're also free to make your function reference only as specific as you need, as per the Swift 2.2+ rules for function-type naming.

(这实际上是对 ObjC 的 @selector() 指令的改进,因为编译器的 -Wundeclared-selector 检查仅验证命名选择器是否存在.Swift 函数您传递给 #selector 的引用检查是否存在、类中的成员身份和类型签名.)

(This is actually an improvement over ObjC's @selector() directive, because the compiler's -Wundeclared-selector check verifies only that the named selector exists. The Swift function reference you pass to #selector checks existence, membership in a class, and type signature.)

对于传递给 #selector 表达式的函数引用,有几个额外的注意事项:

There are a couple of extra caveats for the function references you pass to the #selector expression:

  • 具有相同基本名称的多个函数可以使用上述 函数引用的语法(例如insertSubview(_:at:) vs insertSubview(_:aboveSubview:)).但是如果一个函数没有参数,唯一消除歧义的方法是使用带有函数类型签名的 as 转换(例如 foo as () -> ()vs foo(_:)).
  • Swift 3.0+ 中的属性 getter/setter 对有一种特殊的语法.例如,给定一个 var foo: Int,你可以使用 #selector(getter: MyClass.foo)#selector(setter: MyClass.foo).
  • Multiple functions with the same base name can be differentiated by their parameter labels using the aforementioned syntax for function references (e.g. insertSubview(_:at:) vs insertSubview(_:aboveSubview:)). But if a function has no parameters, the only way to disambiguate it is to use an as cast with the function's type signature (e.g. foo as () -> () vs foo(_:)).
  • There's a special syntax for property getter/setter pairs in Swift 3.0+. For example, given a var foo: Int, you can use #selector(getter: MyClass.foo) or #selector(setter: MyClass.foo).

#selector 不起作用和命名的情况: 有时您没有函数引用来创建选择器(例如,使用动态方法在 ObjC 运行时中注册).在这种情况下,您可以从字符串构造一个 Selector:例如Selector("dynamicMethod:") — 尽管您失去了编译器的有效性检查.这样做时,您需要遵循 ObjC 命名规则,包括每个参数的冒号 (:).

Cases where #selector doesn't work, and naming: Sometimes you don't have a function reference to make a selector with (for example, with methods dynamically registered in the ObjC runtime). In that case, you can construct a Selector from a string: e.g. Selector("dynamicMethod:") — though you lose the compiler's validity checking. When you do that, you need to follow ObjC naming rules, including colons (:) for each parameter.

选择器可用性: 选择器引用的方法必须暴露给 ObjC 运行时.在 Swift 4 中,每个公开给 ObjC 的方法都必须以 @objc 属性开头的声明.(在以前的版本中,您在某些情况下可以免费获得该属性,但现在您必须明确声明它.)

Selector availability: The method referenced by the selector must be exposed to the ObjC runtime. In Swift 4, every method exposed to ObjC must have its declaration prefaced with the @objc attribute. (In previous versions you got that attribute for free in some cases, but now you have to explicitly declare it.)

请记住,private 符号也不会暴露给运行时——您的方法至少需要具有 internal 可见性.

Remember that private symbols aren't exposed to the runtime, too — your method needs to have at least internal visibility.

关键路径:这些与选择器相关但又不完全相同.在 Swift 3 中也有一个特殊的语法:例如chris.valueForKeyPath(#keyPath(Person.friends.firstName)).有关详细信息,请参阅 SE-0062.甚至更多 KeyPathSwift 4 中的内容,因此请确保使用正确的基于 KeyPath 的 API 而不是选择器(如果合适).

Key paths: These are related to but not quite the same as selectors. There's a special syntax for these in Swift 3, too: e.g. chris.valueForKeyPath(#keyPath(Person.friends.firstName)). See SE-0062 for details. And even more KeyPath stuff in Swift 4, so make sure you're using the right KeyPath-based API instead of selectors if appropriate.

您可以在 与 Objective-C API 交互将 Swift 与 Cocoa 和 Objective-C 结合使用.

注意:在 Swift 2.2 之前,Selector 符合 StringLiteralConvertible,因此您可能会发现将裸字符串传递给的旧代码采用选择器的 API.您需要运行Convert to Current Swift Syntax";在 Xcode 中使用 #selector 获取那些.

Note: Before Swift 2.2, Selector conformed to StringLiteralConvertible, so you might find old code where bare strings are passed to APIs that take selectors. You'll want to run "Convert to Current Swift Syntax" in Xcode to get those using #selector.

这篇关于@selector() 在 Swift 中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆