4

I would like to call an @autoclosure parameter inside dispatch_async block.

func myFunc(@autoclosure condition: () -> Bool) {
  dispatch_async(dispatch_get_main_queue()) {
    if condition() {
      println("Condition is true")
    }
  }
}

I get the following error.

Closure use of @noescape parameter may allow it to escape.

Is it possible to call @autoclosure parameter asynchronously?

Tested in Xcode 6.4 (6E23).

Evgenii
  • 36,389
  • 27
  • 134
  • 170

2 Answers2

13

Yes, so long as you declare them @autoclosure(escaping):

Declarations with the autoclosure attribute imply noescape as well, except when passed the optional attribute escaping.

So this should do it:

func myFunc(@autoclosure(escaping) condition: () -> Bool) {
    dispatch_async(dispatch_get_main_queue()) {
        if condition() {
            println("Condition is true")
        }
    }
}
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • 2
    it works it's great but could this be dangerous for user using this api? If it's a closure and let's say it asynchronous we know we have to use `[weak self]` but if it is an escaping autoclosure user won't use `[weak self]` ? – Anthony Mittaz May 22 '15 at 00:13
  • 1
    Yes, definitely. Though if you do reference `self` implicitly, you’ll get a warning by the compiler that you need to reference `self` explicitly to acknowledge the capture (same as with a closure expression) – Airspeed Velocity May 22 '15 at 00:18
  • 1
    And of course bear in mind there’s nothing stopping you calling `myFunc` with an explicit closure as well: `myFunc { [weak self] in self?.p ?? false }` – Airspeed Velocity May 22 '15 at 00:20
  • it's neat that the compiler let us know about self capture sadly [weak self] isn't possible when using short notation `myFunc(true)`, also I am unable to use `myFunc { [weak self] in self?.p ?? false }` – Anthony Mittaz May 22 '15 at 00:53
  • instead have to do something like this: `myApiCall ({ [weak self] in self?.loading = false }())`, triggering a segfault on compile – Anthony Mittaz May 22 '15 at 00:59
  • funny because [Apple Swift blog](https://developer.apple.com/swift/blog/?id=4) has this as per example `assert({ someExpensiveComputation() != 42 })` – Anthony Mittaz May 22 '15 at 01:05
  • `myFunc(true)` doesn’t capture anything. And `myFunc(someLocalVar)` is usually fine too, especially if its a value type. But yeah, I’d be wary of `@autoclosure` in general except for simple stuff like short-circuiting – Airspeed Velocity May 22 '15 at 01:51
1

Updating the answer from Airspeed Velocity, you can pass weak self directly into escaping autoclosure.

var boolValue: Bool = true

func myFunc(condition: @autoclosure @escaping () -> Bool?) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        if let condition = condition() {
            print("Condition is \(condition ? "true" : "false")")
        }
    }
}

func main() {
    weak var weakSelf = self
    myFunc(condition: weakSelf?.boolValue)
}
bodich
  • 1,708
  • 12
  • 31