如何将 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 指示器。