如何将 return 延迟到调用函数 swift
How to delay the return to the calling function swift
在我的应用程序中,用户可以按下一个按钮。这又会导致如下所示的函数调用:
在ViewController.Swift
@IBAction func pickMeUpButton(sender: AnyObject) {
sendPushNotificationController().sendPushNotification("sendRequest",userInfo: defaults.stringForKey("x73")!, userInf23: defaults.stringForKey("x23")! )
locationController.getLocationForShortTime() // --> here i want the timer to finish the 5 seconds before proceeding
activityIndicator.center = self.view.center
activityIndicator.startAnimating()
self.view.addSubview(activityIndicator)
//activityIndicator.stopAnimating()
}
这是 class 调用
的函数
在getUserLocation.swift
func initManager(){
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func getLocationForShortTime(){
initManager()
timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "stopGettingLocation", userInfo: nil, repeats: false)
}
func stopGettingLocation(){
locationManager.stopUpdatingLocation()
}
所以这将使应用程序获取用户位置 5 秒,然后计时器将停止更新。我想要做的是当五秒钟过去并且位置更新停止时然后我希望调用函数继续到下一行。
我虽然有一些使用布尔值的解决方案,但这不是一个好的解决方案。我想可能有更好的方法来做到这一点?
将闭包传递给 getLocationForShortTime
。事情完成后应该是 运行 的那个。我无法真正测试代码,但它可能是这样的:
class Handler { // <- This is the wrapper class for completion closures
private let run: Void -> Void
init(_ run: Void -> Void) { self.run = run }
}
lazy var locationManager: CLLocationManager! = self.lazyLocationManager()
func lazyLocationManager() -> CLLocationManager {
let _locationManager = CLLocationManager()
_locationManager.delegate = self
_locationManager.desiredAccuracy = kCLLocationAccuracyBest
_locationManager.requestAlwaysAuthorization()
return _locationManager
}
func getLocationQuick(onComplete: Void -> Void) { // <- This takes the closure
locationManager.startUpdatingLocation()
let timer = NSTimer.scheduledTimerWithTimeInterval(
5,
target: self,
selector: "gotLocationQuick:",
userInfo: Handler(onComplete), // <- Here you wrap the completion closure
repeats: false // and pass it to the timer
)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
}
func gotLocationQuick(timer: NSTimer) {
locationManager.stopUpdatingLocation()
let completionHandler = timer.userInfo as! Handler
completionHandler.run()
}
@IBAction func pickMeUpButton(sender: AnyObject) {
sendPushNotificationController().sendPushNotification(
"sendRequest",
userInfo: defaults.stringForKey("x73")!,
userInf23: defaults.stringForKey("x23")!
)
activityIndicator.center = self.view.center
self.view.addSubview(activityIndicator)
activityIndicator.startAnimating()
locationController.getLocationQuick() { // <- You post the request for
activityIndicator.stopAnimating() // geolocation and indicate the code
} // to be run once it's finished
}
要延迟 function-call,您可以使用 dispatch_after
。它的语法有点难看,所以你也可以使用这个延迟函数:
/// delays the execution of the passed function
func delay(delay: Double, closure: ()->()) {
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))),
dispatch_get_main_queue(),
closure)
}
// calling directly (locationManager gets captured; which is in this case negligible to consider)
delay(5.0, closure: locationManager.stopUpdatingLocation)
// or indirect through your function
delay(5.0, closure: stopGettingLocation)
其他人告诉过你该做什么,但没有告诉你为什么。
你需要调整一下思路。
对于像 iPhone/iPad 这样的 event-driven 设备,您不能在主线程上停止处理 5 秒。 UI 会锁定,几秒钟后系统会终止您的应用程序。
相反,您要做的是在延迟后调用代码块(闭包)。
您可以这样重写您的函数:
@IBAction func pickMeUpButton(sender: AnyObject)
{
sendPushNotificationController().sendPushNotification("sendRequest",
userInfo: defaults.stringForKey("x73")!,
userInf23: defaults.stringForKey("x23")! )
initManager()
//Start the activity indicator during the delay
activityIndicator.center = self.view.center
self.view.addSubview(activityIndicator)
activityIndicator.startAnimating()
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC))),
dispatch_get_main_queue())
{
//The code in the braces gets run after the delay value
locationManager.stopUpdatingLocation()
activityIndicator.stopAnimating()
}
//dispatch_after returns immediately, so code here will run before
//the delay period passes.
}
该按钮操作代码将:
调用 initManager 启动位置管理器运行。
立即创建一个 activity 指示器,将其添加到视图控制器的内容视图中,然后开始旋转。
然后,对 dispatch_after 的调用将在 运行 大括号中的代码之前等待 5 秒,这将停止位置管理器并停止 activity 指示器。
在我的应用程序中,用户可以按下一个按钮。这又会导致如下所示的函数调用:
在ViewController.Swift
@IBAction func pickMeUpButton(sender: AnyObject) {
sendPushNotificationController().sendPushNotification("sendRequest",userInfo: defaults.stringForKey("x73")!, userInf23: defaults.stringForKey("x23")! )
locationController.getLocationForShortTime() // --> here i want the timer to finish the 5 seconds before proceeding
activityIndicator.center = self.view.center
activityIndicator.startAnimating()
self.view.addSubview(activityIndicator)
//activityIndicator.stopAnimating()
}
这是 class 调用
的函数在getUserLocation.swift
func initManager(){
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func getLocationForShortTime(){
initManager()
timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "stopGettingLocation", userInfo: nil, repeats: false)
}
func stopGettingLocation(){
locationManager.stopUpdatingLocation()
}
所以这将使应用程序获取用户位置 5 秒,然后计时器将停止更新。我想要做的是当五秒钟过去并且位置更新停止时然后我希望调用函数继续到下一行。
我虽然有一些使用布尔值的解决方案,但这不是一个好的解决方案。我想可能有更好的方法来做到这一点?
将闭包传递给 getLocationForShortTime
。事情完成后应该是 运行 的那个。我无法真正测试代码,但它可能是这样的:
class Handler { // <- This is the wrapper class for completion closures
private let run: Void -> Void
init(_ run: Void -> Void) { self.run = run }
}
lazy var locationManager: CLLocationManager! = self.lazyLocationManager()
func lazyLocationManager() -> CLLocationManager {
let _locationManager = CLLocationManager()
_locationManager.delegate = self
_locationManager.desiredAccuracy = kCLLocationAccuracyBest
_locationManager.requestAlwaysAuthorization()
return _locationManager
}
func getLocationQuick(onComplete: Void -> Void) { // <- This takes the closure
locationManager.startUpdatingLocation()
let timer = NSTimer.scheduledTimerWithTimeInterval(
5,
target: self,
selector: "gotLocationQuick:",
userInfo: Handler(onComplete), // <- Here you wrap the completion closure
repeats: false // and pass it to the timer
)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
}
func gotLocationQuick(timer: NSTimer) {
locationManager.stopUpdatingLocation()
let completionHandler = timer.userInfo as! Handler
completionHandler.run()
}
@IBAction func pickMeUpButton(sender: AnyObject) {
sendPushNotificationController().sendPushNotification(
"sendRequest",
userInfo: defaults.stringForKey("x73")!,
userInf23: defaults.stringForKey("x23")!
)
activityIndicator.center = self.view.center
self.view.addSubview(activityIndicator)
activityIndicator.startAnimating()
locationController.getLocationQuick() { // <- You post the request for
activityIndicator.stopAnimating() // geolocation and indicate the code
} // to be run once it's finished
}
要延迟 function-call,您可以使用 dispatch_after
。它的语法有点难看,所以你也可以使用这个延迟函数:
/// delays the execution of the passed function
func delay(delay: Double, closure: ()->()) {
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))),
dispatch_get_main_queue(),
closure)
}
// calling directly (locationManager gets captured; which is in this case negligible to consider)
delay(5.0, closure: locationManager.stopUpdatingLocation)
// or indirect through your function
delay(5.0, closure: stopGettingLocation)
其他人告诉过你该做什么,但没有告诉你为什么。
你需要调整一下思路。
对于像 iPhone/iPad 这样的 event-driven 设备,您不能在主线程上停止处理 5 秒。 UI 会锁定,几秒钟后系统会终止您的应用程序。
相反,您要做的是在延迟后调用代码块(闭包)。
您可以这样重写您的函数:
@IBAction func pickMeUpButton(sender: AnyObject)
{
sendPushNotificationController().sendPushNotification("sendRequest",
userInfo: defaults.stringForKey("x73")!,
userInf23: defaults.stringForKey("x23")! )
initManager()
//Start the activity indicator during the delay
activityIndicator.center = self.view.center
self.view.addSubview(activityIndicator)
activityIndicator.startAnimating()
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC))),
dispatch_get_main_queue())
{
//The code in the braces gets run after the delay value
locationManager.stopUpdatingLocation()
activityIndicator.stopAnimating()
}
//dispatch_after returns immediately, so code here will run before
//the delay period passes.
}
该按钮操作代码将:
调用 initManager 启动位置管理器运行。
立即创建一个 activity 指示器,将其添加到视图控制器的内容视图中,然后开始旋转。
然后,对 dispatch_after 的调用将在 运行 大括号中的代码之前等待 5 秒,这将停止位置管理器并停止 activity 指示器。