我想在将来安排一个函数调用。我正在使用Swift。
我想回调一个私有的方法并返回一个Promise(来自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在这做什么?
无论如何,建议我在方法@objc
前添加connect
。精细。好吧,我不能,因为显然Method cannot be marked @objc because its result type cannot be represented in Objective-C
如果我想使用Objective-C,我不会写Swift ......
还有另一个scheduledTimerWithTimeInterval
NSTimer.scheduledTimerWithTimeInterval(ti: NSTimeInterval, invocation: NSInvocation, repeats: Bool)
但是从我读过的NSInvocation
来看,并不是斯威夫特的事情......
所以我最终创建了一个包装器,除了调用connect
并返回Objective C可以理解的Void
之外什么都不做。它有效,但感觉非常愚蠢。有更好的Swift方式吗?
额外奖励:为什么javascript可以像setTimeout(this.connect, 1)
一样简单地执行此操作而Swift没有我可以找到的内置方式?
答案 0 :(得分:4)
从iOS 10和Swift 3开始,可以使用带有块闭包的(NS)Timer,从而避免在计时器触发时调用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
装饰器之外,使用此技术还可以调用包含非Objective-C兼容参数类型(如枚举和选项)的方法。
setTimeout(this.connect, 1)
,如果您不需要取消它,可以在Swift 3中进行更直接的类比:
DispatchQueue.Main.asyncAfter(deadline: .now() + 1.0, execute { self.connect() })
考虑到你实际上可以选择运行哪个线程,这是非常接近的; - )
答案 1 :(得分:1)
什么是Objective-C在这做什么?
需要Objective-C的原因是它动态地绑定了#34; call" (在Objective-C中没有调用)在运行时,而Swift无法做到这一点。 Swift无法在定时器类中使用"调用" a"功能"在NSTimer
的编译时间不知道。
顺便说一句:NSTimer
使用NSInvocation
(或类似的无法使用的技术)进行"调用"。因此NSTimer
的使用并不是更加明确,但对后期绑定的需求更加模糊,以使Swift开发人员感觉更好。
如果我想使用Objective-C我不会写Swift ......
即使您的代码完全是用Swift编写的,它也会从Objective-C的后期绑定中获得大量好处。 Cocoa的许多核心技术都无法在Swift中编写,包括响应链,撤消管理器,核心数据,动画......(另一方面,您可以定义一个运算符,在软件工程中取得了哪些重大进展并描述了整个故事。)
答案 2 :(得分:0)
请记住,Swift 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()
。
更多信息引用方法的Objective-C选择器 here
答案 3 :(得分:0)
有两种方法可以调用计时器:
// 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")
}
答案 4 :(得分:0)
即使您正在使用swift,Objective-C也需要可以访问NSTimer的回调。就我而言,它意味着两件事:
@objc
修饰私有方法,因为默认情况下,Swift类的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)
}
}