3

I have a question concerning the swift implementation of the method mentioned in the title. If I do this:

leadingSpaceConstraint.constant = 0
UIView.animateWithDuration(0.3, animations: {
    self.view.layoutIfNeeded()
}, completion: { (complete: Bool) in
    self.navigationController.returnToRootViewController(true)
})

I get the following problem: Missing argument for parameter 'delay' in call. This only happens if I have the self.navigationController.returnToRootViewController() in the completion part. If I extract that statement into a seperate method like this:

leadingSpaceConstraint.constant = 0
UIView.animateWithDuration(0.3, animations: {
    self.view.layoutIfNeeded()
}, completion: { (complete: Bool) in
    self.returnToRootViewController()
})

func returnToRootViewController() {
    navigationController.popToRootViewControllerAnimated(true)
}

Then it works perfectly and does exactly what I want. Of course this does not seem to be the ideal solution and more like a work around. Can anyone tell me what I did wrong or why Xcode (beta 6) is behaving this way?

Fattie
  • 27,874
  • 70
  • 431
  • 719
c2programming
  • 235
  • 3
  • 17
  • This has been a common cause of questions for a long time. It always manifests differently...see the answer here:http://stackoverflow.com/questions/24338842/what-am-i-doing-wrong-in-swift-for-calling-this-objective-c-block-api-call/24347498#24347498 – Jack Aug 31 '14 at 20:49
  • possible duplicate of [animateWithDuration:animations:completion: in Swift](http://stackoverflow.com/questions/24296023/animatewithdurationanimationscompletion-in-swift) – Jack Aug 31 '14 at 20:50
  • Ha. I knew this had been answered before, but wasn't finding the dupe. (Actually, I'm pretty sure I've answered it before that dupe, but I can't find it in my history either.) – rickster Aug 31 '14 at 21:17
  • Try changing `(complete:Bool) in` to `(complete:Bool) -> Void in` – nielsbot Dec 01 '18 at 07:23

1 Answers1

11

I presume you mean popToRootViewControllerAnimated in your first snippet, since returnToRootViewController isn't a method on UUNavigationController.

Your problem is that popToRootViewControllerAnimated has a return value (the array of view controllers removed from the navigation stack). This causes trouble even though you're trying to discard the return value.

When Swift sees a function/method call with a return value as the last line of a closure, it assumes you're using the closure shorthand syntax for implicit return values. (The kind that lets you write things like someStrings.map({ $0.uppercaseString }).) Then, because you have a closure that returns something in a place where you're expected to pass a closure that returns void, the method call fails to type-check. Type checking errors tend to produce bad diagnostic messages — I'm sure it'd help if you filed a bug with the code you have and the error message it's producing.

Anyhow, you can work around this by making the last line of the closure not be an expression with a value. I favor an explicit return:

UIView.animateWithDuration(0.3, animations: {
    self.view.layoutIfNeeded()
}, completion: { (complete: Bool) in
    self.navigationController.popToRootViewControllerAnimated(true)
    return
})

You can also assign that popToRootViewControllerAnimated call to an unused variable or put an expression that does nothing after it, but I think the return statement is clearest.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • 1
    Did you mean you could use `_ = self.navigationController.popToRootViewControllerAnimated(true)`? Another possibility: explicitly declare the return type of your closure to be `Void` – nielsbot Dec 01 '18 at 07:23