Swift的performSelector:withObject:afterDelay:不可用。

144

我有一个Objective C的应用程序,现在正在转换为Swift。在Objective C中,我有这个方法:

[self.view performSelector:@selector(someSelector) withObject:self afterDelay:0.1f];

我正在使用Swift,但我无法弄清楚如何实现这一点。我尝试过:

self.view.performSelector(Selector("someSelector"), withObject: self, afterDelay: 0.1)

这是我得到的错误:'performSelector' is unavailable: 'performSelector' methods are unavailable

我该使用什么调用来调用一个带有afterDelay参数的方法?

更新

这是我最终使用的代码:

extension NSObject {

    func callSelectorAsync(selector: Selector, object: AnyObject?, delay: NSTimeInterval) -> NSTimer {

        let timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: selector, userInfo: object, repeats: false)
        return timer
    }

    func callSelector(selector: Selector, object: AnyObject?, delay: NSTimeInterval) {

        let delay = delay * Double(NSEC_PER_SEC)
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
        dispatch_after(time, dispatch_get_main_queue(), {
            NSThread.detachNewThreadSelector(selector, toTarget:self, withObject: object)
        })
    }
}

10
我不同意。我不是在问如何执行Selector,而是在问如何延迟执行一个Selector。 - Cody Winton
同样的问题在那里得到了解答。使用GCD和dispatch_after或dispatch_async。 - David Berry
9
@David:那里没有回答你的问题。dispatch_after 使用调度队列,而 performSelector:afterDelay: 使用当前运行循环。它们是不同的。 - user102008
你好,我在我的项目中使用了你的代码,想让你知道:https://github.com/goktugyil/CozyLoadingActivity - Esqarrouth
@Esq - 太棒了,伙计!真是太好了。 - Cody Winton
self.perform(#selector(self.someSelector), with: self, afterDelay: 0.1)自我执行(#选择器(self.someSelector), 使用: self, 延迟: 0.1) - Rajeev Udayan
3个回答

166

Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    // your function here
}

Swift 3

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(0.1)) {
    // your function here
}

Swift 2

let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) 
dispatch_after(dispatchTime, dispatch_get_main_queue(), { 
    // your function here 
})

2
但这是不同的。dispatch_after 与调度队列一起工作。performSelector:afterDelay:NSTimer 在运行循环上工作。 - user102008
4
你应该将_dispatch_time_t_作为第一个参数传递。 var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))) dispatch_after(dispatchTime, dispatch_get_main_queue(), { // 在这里写入你的函数 }) - Vladimirs Matusevics
9
在Swift 3中,您可以这样做... DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // 做一些事情 } - 365SplendidSuns
5
对于最新版本的Swift,创建dispatchTime的正确方法如下: let dispatchTime = DispatchTime.now() + 0.1 - Tung Fam
1
这是我使用的代码: DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // } - Thomas Jeans
显示剩余9条评论

112

你可以这样做:

var timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("someSelector"), userInfo: nil, repeats: false)

func someSelector() {
    // Something after a delay
}

SWIFT 3

let timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(someSelector), userInfo: nil, repeats: false)

func someSelector() {
    // Something after a delay
}

1
好的,谢谢。我会尝试的。 - Cody Winton
@JasonCrump:只要该方法被标记为 @objcdynamic,它就能够正常运行。 - user102008
1
请注意,这仅适用于没有参数的方法直接转换。如果它们需要一个参数,在这种情况下将传递NSTimer,而不是像performSelector:afterDelay:中给定的对象。此外,该方法不能返回任何内容。 - user102008
另外,请注意,此方法无法在没有运行循环的线程上工作——即GCD后台线程。 - Sean
1
你好,我在我的项目中使用了你的代码,想让你知道:https://github.com/goktugyil/CozyLoadingActivity - Esqarrouth
显示剩余4条评论

10

Swift是静态类型的,所以performSelector:方法会被淘汰。

相反,使用GCD将适当的块分派到相关队列中-在这种情况下,它很可能是主队列,因为您似乎正在进行UIKit工作。

编辑:有关的performSelector:也明显缺少 NSRunLoop文档的Swift版本(“1个Objective-C符号已隐藏”)因此您不能直接使用它。基于此和它在Swift版的NSObject中的缺失,我认为苹果在这里的想法非常明确。


1
这是一个问题。dispatch_get_current_queue已经被弃用,而获取一个队列来在当前线程上运行(带有runloop)并不容易。performSelector:方法有其作用,并且它们不会消失。 - Léo Natan
1
我的评论更多是针对你的评论,而不是问题本身。如果performSelector:最终被人为禁用,那么一个简单的Objective C类别包装器就可以解决问题。 - Léo Natan
1
认可和必要性是两回事。 - Léo Natan
1
@newacct 我在猜测,没有内部消息,但现在只能说performSelector是安全的;runloops与事件调度特别是网络访问有关。但你可以很容易地想象它们将成为纯粹的内部事务。我认为再过五年我们就要和Objective-C说再见了。Java桥没有持续那么长时间,如果Swift适合系统编程的热情是正确的,我们将越来越多地谈论允许Objective-C访问系统的桥梁。虽然这只是猜测,而不是知识。 - Tommy
@FizzBuzz,但要注意它们仅适用于Objective-C类(即来自真正的Objective-C和Swift类,并通过任何路由从NSObject继承的类)——否则您将会收到“class XXX does not implement methodSignatureForSelector:” 的错误提示。 - Tommy
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接