如何向包含 dispatch_after() 的函数添加回调?
How do I add a callback to a func that contains a dispatch_after()?
我想在几秒钟后关闭 UIAlertView(不需要 'ok' 按钮)。
经过一些研究,我发现我可以使用 dispatch_after 作为最终解除警报的延迟:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC)) // ...Int64.init() struct in Swift.
),
dispatch_get_main_queue(), closure)
}
来源:Using dispatch_after vs NSTimer
上面的代码工作正常,但我想编辑闭包以允许传递 sender:UIViewController 参数。这就是我感到困惑的地方。
dispatch_after() 格式为:
func dispatch_after(_ when: dispatch_time_t, _ queue:
dispatch_queue_t, _ block: dispatch_block_t)
这是我尝试过的(错误):
func delay(delay:Double, closure:(sender:UIViewController)->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC)) // ...Int64.init() struct in Swift.
),
dispatch_get_main_queue(), closure:(sender:UIViewController) in {
})
}
问题:如何解决这个问题,使 block/closure 参数包含回调引用 ('sender:UIViewController')?
你不需要"pass"sender
来关闭。您只需要在闭包中引用 sender
。
这被称为 capture
,它是闭包的有用之处之一。闭包将 capture
引用 sender
并带走它。就像魔术一样。
所以把闭包写在sender
范围内的地方。在闭包内引用 sender
。然后,将闭包传递给 delay
,一切都会正常工作:
func closeAlert(sender: UIVewController) {
let closure: () -> () = {
doSomethingWith(sender)
}
delay(3, closure: closure)
}
同样,秘诀在于闭包捕获对 sender
的引用,当闭包传递给 delay
.
以下 (abridged) 代码显示我的警报对话框(没有按钮)几秒钟然后消失。
我正在考虑使用 NSTimer,但了解到这是不明智的。
使用 Swift + dispatch_after() 是真正的方法。
showAlert(sender: self, withTitle: "No Blisses", withMessage: "You don't have any Blisses to show.", alertPurpose: .timed)
enum AlertPurpose:Int {
case none = 0 // ...default: no alert button.
case simple // ...generic OK response.
case timed
case startBliss
case noVideo
case createdHashtag
case missingProfileImage
case profileSaved
case settings
}
func closeAlert(sender: UIViewController) {
let closure: () -> () = {
sender.dismissViewControllerAnimated(true, completion: nil)
}
delay(3, closure)
}
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
...
...
...
} else if alertPurpose == .timed {
closeAlert(sender as! UIViewController)
我想在几秒钟后关闭 UIAlertView(不需要 'ok' 按钮)。
经过一些研究,我发现我可以使用 dispatch_after 作为最终解除警报的延迟:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC)) // ...Int64.init() struct in Swift.
),
dispatch_get_main_queue(), closure)
}
来源:Using dispatch_after vs NSTimer
上面的代码工作正常,但我想编辑闭包以允许传递 sender:UIViewController 参数。这就是我感到困惑的地方。
dispatch_after() 格式为:
func dispatch_after(_ when: dispatch_time_t, _ queue: dispatch_queue_t, _ block: dispatch_block_t)
这是我尝试过的(错误):
func delay(delay:Double, closure:(sender:UIViewController)->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC)) // ...Int64.init() struct in Swift.
),
dispatch_get_main_queue(), closure:(sender:UIViewController) in {
})
}
问题:如何解决这个问题,使 block/closure 参数包含回调引用 ('sender:UIViewController')?
你不需要"pass"sender
来关闭。您只需要在闭包中引用 sender
。
这被称为 capture
,它是闭包的有用之处之一。闭包将 capture
引用 sender
并带走它。就像魔术一样。
所以把闭包写在sender
范围内的地方。在闭包内引用 sender
。然后,将闭包传递给 delay
,一切都会正常工作:
func closeAlert(sender: UIVewController) {
let closure: () -> () = {
doSomethingWith(sender)
}
delay(3, closure: closure)
}
同样,秘诀在于闭包捕获对 sender
的引用,当闭包传递给 delay
.
以下 (abridged) 代码显示我的警报对话框(没有按钮)几秒钟然后消失。
我正在考虑使用 NSTimer,但了解到这是不明智的。
使用 Swift + dispatch_after() 是真正的方法。
showAlert(sender: self, withTitle: "No Blisses", withMessage: "You don't have any Blisses to show.", alertPurpose: .timed)
enum AlertPurpose:Int {
case none = 0 // ...default: no alert button.
case simple // ...generic OK response.
case timed
case startBliss
case noVideo
case createdHashtag
case missingProfileImage
case profileSaved
case settings
}
func closeAlert(sender: UIViewController) {
let closure: () -> () = {
sender.dismissViewControllerAnimated(true, completion: nil)
}
delay(3, closure)
}
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
...
...
...
} else if alertPurpose == .timed {
closeAlert(sender as! UIViewController)