Swift - scheduledTimerWithTimeInterval - NSInvocation
我想在未来安排函数调用。我正在使用Swift。Swift - scheduledTimerWithTimeInterval - NSInvocation
我要回调是私有的,返回一个承诺(从PromiseKit)的方法
我见过使用
NSTimer.scheduledTimerWithTimeInterval(ti: NSTimeInterval, target: AnyObject, selector: Selector, userInfo: AnyObject?, repeats: Bool)
精细的所有例子。我试过了
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "connect", userInfo: nil, repeats: false)
这个失败与No method declared with Objective-C selector 'connect'
。
Objective-C在这里做什么?
无论如何建议我在我的方法connect
前添加@objc
。精细。嗯,我不能因为显然Method cannot be marked @objc because its result type cannot be represented in Objective-C
如果我想用客观-C我不会写斯威夫特...
还有一个scheduledTimerWithTimeInterval
是
NSTimer.scheduledTimerWithTimeInterval(ti: NSTimeInterval, invocation: NSInvocation, repeats: Bool)
但是,从我读过NSInvocation
不是斯威夫特的事情...
所以我结束了创建一个包装,什么也不做其他比调用connect
并返回Void
这一目标C能understan d。它有效,但感觉非常愚蠢。有更好的Swift方法吗?
奖励:为什么JavaScript可以这么做,就像setTimeout(this.connect, 1)
一样,Swift没有内置的方法可以找到?
与iOS 10和夫特3开始,它是能够使用(NS)定时器与块闭合,从而避免Objective-C中选择的调用当计时器触发:
if #available(iOS 10.0, *) {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { (Timer) in
self.connect() // per the OP's example
})
}
除了避免@objc
装饰,使用这种技术允许你调用方法,其包括非目标C兼容的参数类型,例如枚举和自选。
回复:setTimeout(this.connect, 1)
从JavaScript,如果你不需要将其取消,斯威夫特3更直接的类比可能是:
DispatchQueue.Main.asyncAfter(deadline: .now() + 1.0, execute { self.connect() })
这是相当的接近因为你确实有一个选择其中的线程运行;-)
记住雨燕2.2 /的Xcode 7.3已使用选择的新方法:Selector("funcName")
改为#selector(ClassName.funcName)
你应该使用#selector
:
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(YourClass.connect), userInfo: nil, repeats: false)
或Selector("connect")
,但请记住,你会收到一个警告:
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("connect"), userInfo: nil, repeats: false)
也看看this为了知道如何使用Selector()
。
更多信息引用一个方法 here的Objective-C的选择。
有2种方式,你可以调用一个计时器:
// Specify the selector name as String
// Swift will give you a warning but this is handy if you have the function's name stored
// as a variable or need some dynamism
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("timerFired"), userInfo: nil, repeats: false)
// The recommended way since Swift 2.2/2.3 (can't remeber exactly)
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(MyClass.timerFired), userInfo: nil, repeats: false)
而且两者假设你有这样的功能:
func timerFired() {
print("Hello world")
}
什么是Objective-C的在这里做什么?
需要Objective-C的原因是它在运行时动态地绑定了“调用”(它在Objective-C中没有调用),而Swift不能这样做。 Swift无法在定时器类中拥有“调用”在编译时NSTimer
处未知的“函数”的代码。
作者:NSTimer
使用NSInvocation
(或类似unswifty技术)做“呼叫”。因此,NSTimer
的使用不会更快速,但对后期绑定的需求更加混淆,以使Swift开发人员感觉更好。
如果我想用客观-C我不会写斯威夫特...
即使你的代码是完全用斯威夫特,它需要从Objective-C的后期绑定群众利益。 Cocoa的许多核心技术都不可能在Swift中编写,包括响应者链,撤消管理器,核心数据,动画......(另一方面,您可以定义一个操作符,软件工程中的一个重大进展,并描述整个故事)。
即使使用swift,NSTimer的回调也需要Objective-C的访问。在我的情况下,这意味着两件事:
- 修饰私有方法
@objc
,因为默认私有方法不能从Objective-C从Swift类访问。 - 将我的方法包装在调用它的方法中,并且不返回任何内容,以便回调函数返回void。这是必要的,因为Objective-C不知道如何处理
Promise
类型。
所以最终它看起来像:
import PromiseKit
class bla : NSObject {
private func myCallback() -> Promise<Void> {
return Promise { fullfill, reject in
// ...
}
}
@objc private func myCallbackWrap -> Void {
myCallback()
}
func startTimeout() -> Void {
NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: #selector(myCallbackWrap), userInfo: nil, repeats: false)
}
}
非常好,谢谢! – Guig