Swift中的@selector()?

本文翻译自:@selector() in Swift?

I'm trying to create an NSTimer in Swift but I'm having some trouble. 我正在尝试在Swift创建NSTimer ,但遇到了一些麻烦。

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

test() is a function in the same class. test()是同一类中的函数。


I get an error in the editor: 我在编辑器中收到一个错误:

Could not find an overload for 'init' that accepts the supplied arguments 找不到接受提供的参数的'init'的重载

When I change selector: test() to selector: nil the error disappears. 当我将selector: test()更改为selector: nil ,错误消失了。

I've tried: 我试过了:

  • selector: test()
  • selector: test
  • selector: Selector(test())

But nothing works and I can't find a solution in the references. 但是没有任何效果,我在参考文献中找不到解决方案。


#1楼

参考:https://stackoom.com/question/1cjUA/Swift中的-selector


#2楼

Swift itself doesn't use selectors — several design patterns that in Objective-C make use of selectors work differently in Swift. Swift 本身不使用选择器-在Objective-C中,使用选择器的几种设计模式在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.) (例如,使用任选的链上的协议类型或is / as测试来代替respondsToSelector:和使用闭随时随地可以代替performSelector:为更好的类型/存储器的安全性。)

But there are still a number of important ObjC-based APIs that use selectors, including timers and the target/action pattern. 但是仍然有许多重要的基于ObjC的API使用选择器,包括计时器和目标/操作模式。 Swift provides the Selector type for working with these. Swift提供了用于处理这些内容的Selector类型。 (Swift automatically uses this in place of ObjC's SEL type.) (Swift会自动使用它代替ObjC的SEL类型。)

In Swift 2.2 (Xcode 7.3) and later (including Swift 3 / Xcode 8 and Swift 4 / Xcode 9): 在Swift 2.2(Xcode 7.3)和更高版本(包括Swift 3 / Xcode 8和Swift 4 / Xcode 9)中:

You can construct a Selector from a Swift function type using the #selector expression. 您可以使用#selector表达式从Swift函数类型构造一个Selector

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)

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). Swift编译器会检查函数引用,因此您只能将#selector表达式与实际存在且有资格用作选择器的类/方法对一起使用(请参见下面的“选择器可用性”)。 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 . 根据Swift 2.2+函数类型命名规则,您还可以随意根据需要指定函数引用。

(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.) (这实际上是对ObjC的@selector()指令的改进,因为编译器的-Wundeclared-selector检查仅验证命名选择器的存在。传递给#selector的Swift函数引用将检查存在性,类的成员身份和类型签名。 )

There are a couple of extra caveats for the function references you pass to the #selector expression: 对于传递给#selector表达式的函数引用,还有一些其他警告:

  • Multiple functions with the same base name can be differentiated by their parameter labels using the aforementioned syntax for function references (eg insertSubview(_:at:) vs insertSubview(_:aboveSubview:) ). 使用上述用于函数引用的语法 (例如, insertSubview(_:at:)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 (eg foo as () -> () vs foo(_:) ). 但是,如果一个函数没有参数,消除歧义的唯一方式是使用as投用函数的类型签名(例如foo as () -> () VS foo(_:) )。
  • There's a special syntax for property getter/setter pairs in Swift 3.0+. Swift 3.0+中的属性getter / setter对有一种特殊的语法。 For example, given a var foo: Int , you can use #selector(getter: MyClass.foo) or #selector(setter: MyClass.foo) . 例如,给定var foo: Int ,可以使用#selector(getter: MyClass.foo)#selector(setter: MyClass.foo)

General notes: 一般注意事项:

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). #selector无法使用和命名的情况:有时您没有函数引用来创建选择器(例如,使用在ObjC运行时中动态注册的方法)。 In that case, you can construct a Selector from a string: eg Selector("dynamicMethod:") — though you lose the compiler's validity checking. 在那种情况下,您可以从字符串构造一个Selector :例如Selector("dynamicMethod:") —尽管您丢失了编译器的有效性检查。 When you do that, you need to follow ObjC naming rules, including colons ( : ) for each parameter. 当你这样做,你需要遵循ObjC的命名规则,包括冒号( : )每个参数。

Selector availability: The method referenced by the selector must be exposed to the ObjC runtime. 选择器可用性:选择器引用的方法必须公开给ObjC运行时。 In Swift 4, every method exposed to ObjC must have its declaration prefaced with the @objc attribute. 在Swift 4中,每个公开给ObjC的方法都必须在其声明的前面加上@objc属性。 (In previous versions you got that attribute for free in some cases, but now you have to explicitly declare it.) (在以前的版本中,某些情况下您可以免费获得该属性,但是现在您必须显式声明它。)

Remember that private symbols aren't exposed to the runtime, too — your method needs to have at least internal visibility. 请记住, private符号也不会暴露给运行时-您的方法至少需要具有internal可见性。

Key paths: These are related to but not quite the same as selectors. 关键路径:这些路径与选择器相关,但并不完全相同。 There's a special syntax for these in Swift 3, too: eg chris.valueForKeyPath(#keyPath(Person.friends.firstName)) . Swift 3中也有特殊的语法:例如chris.valueForKeyPath(#keyPath(Person.friends.firstName)) See SE-0062 for details. 有关详细信息,请参见SE-0062 And even more KeyPath stuff in Swift 4 , so make sure you're using the right KeyPath-based API instead of selectors if appropriate. 还有Swift 4中的更多KeyPath内容 ,因此请确保您使用的是正确的基于KeyPath的API,而不是适当的选择器。

You can read more about selectors under Interacting with Objective-C APIs in Using Swift with Cocoa and Objective-C . 您可以在“ 将Swift与Cocoa和Objective-C结合使用”中的“ 与Objective-C API交互”下阅读有关选择器的更多信息。

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. 注意:在Swift 2.2之前, Selector符合StringLiteralConvertible ,因此您可能会发现旧代码,其中裸露的字符串被传递到采用选择器的API。 You'll want to run "Convert to Current Swift Syntax" in Xcode to get those using #selector . 您将需要在Xcode中运行“转换为当前的Swift语法”,以使用#selector获得它们。


#3楼

Here's a quick example on how to use the Selector class on Swift: 这是一个有关如何在Swift上使用Selector类的快速示例:

override func viewDidLoad() {
    super.viewDidLoad()

    var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
    self.navigationItem.rightBarButtonItem = rightButton
}

func method() {
    // Something cool here   
}

Note that if the method passed as a string doesn't work, it will fail at runtime, not compile time, and crash your app. 请注意,如果以字符串形式传递的方法不起作用,它将在运行时失败,而不是在编译时失败,并导致应用崩溃。 Be careful 小心


#4楼

Selectors are an internal representation of a method name in Objective-C. 选择器是Objective-C中方法名称的内部表示。 In Objective-C "@selector(methodName)" would convert a source-code method into a data type of SEL. 在Objective-C中,“ @ selector(methodName)”会将源代码方法转换为SEL的数据类型。 Since you can't use the @selector syntax in Swift (rickster is on point there), you have to manually specify the method name as a String object directly, or by passing a String object to the Selector type. 由于您不能在Swift中使用@selector语法(此处就是rickster),因此您必须直接将方法名称直接指定为String对象,或者将String对象传递给Selector类型。 Here is an example: 这是一个例子:

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:"logout"
)

or 要么

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)

#5楼

Also, if your (Swift) class does not descend from an Objective-C class, then you must have a colon at the end of the target method name string and you must use the @objc property with your target method eg 另外,如果您的(Swift)类不是Objective-C类的子类,那么您必须在目标方法名称字符串的末尾加一个冒号,并且必须将@objc属性与目标方法一起使用,例如

var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))

@objc func method() {
    // Something cool here   
} 

otherwise you will get a "Unrecognised Selector" error at runtime. 否则,您将在运行时收到“无法识别的选择器”错误。


#6楼

you create the Selector like below. 您可以如下所示创建选择器。
1. 1。

UIBarButtonItem(
    title: "Some Title",
    style: UIBarButtonItemStyle.Done,
    target: self,
    action: "flatButtonPressed"
)

2. 2。

flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)

Take note that the @selector syntax is gone and replaced with a simple String naming the method to call. 请注意,@ selector语法已消失,并被命名为要调用的方法的简单String取代。 There's one area where we can all agree the verbosity got in the way. 在一个领域中,我们都可以同意冗长的方式。 Of course, if we declared that there is a target method called flatButtonPressed: we better write one: 当然,如果我们声明有一个名为flatButtonPressed的目标方法:我们最好编写一个:

func flatButtonPressed(sender: AnyObject) {
  NSLog("flatButtonPressed")
}

set the timer: 设置计时器:

    var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, 
                    target: self, 
                    selector: Selector("flatButtonPressed"), 
                    userInfo: userInfo, 
                    repeats: true)
    let mainLoop = NSRunLoop.mainRunLoop()  //1
    mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode) //2 this two line is optinal

In order to be complete, here's the flatButtonPressed 为了完整,这里是flatButtonPressed

func flatButtonPressed(timer: NSTimer) {
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值