How to add @noescape annotation to optional closur

2019-02-21 12:46发布

问题:

My function has this signature:

func foo(bar: String, baz: ((String) -> ())? = nil)

And now I want to make unecessary to escape self inside the given closure. But when I try this:

func foo(bar: String, @noescape baz: ((String) -> ())? = nil)

The compiler complains:

@noescape may only be applied to parameters of function type

Is it possible to use it in optional parameters?

回答1:

Requirements

If your requirements are the following:

  • the baz param is a closure
  • the baz param is marked with @noescape (because you want to omit self in the closure code)
  • the baz param can be omitted during the invocation of foo

Solution

Then you can use the following syntax

func foo(bar: String, @noescape baz: ((String) -> ()) = { _ in } ) {

}

As you can see the main difference from your code is that:

  • here baz is not an optional type (but it's an "optional parameter")
  • and its default value is an empty closure not a nil value.

Examples

As you requested you can now pass a closure to baz without the need of using self

class Boo {
    let world = "world"
    func boo() {
        foo("hello") { (something) -> () in
            print(world)
        }
    }
}

And you can also omit the baz param

class Boo {
    let world = "world"
    func boo() {
        foo("hello")
    }
}

Update: using a closure with return type different from Void

In a comment below users TadeasKriz asked about how to use this approach with a closure having the return value different the Void.

Here it is the solution

func foo(bar: String, @noescape baz: ((String) -> (Int)) = { _ in return 0 } ) {

}

Here the baz param does required a closure with 1 param of type String and a return value of type Int. As you can see I added a default value to the param, a closure that does return 0. Please note that the default closure will never be used so you can replace 0 with any Int value you want.

Now you can decide whether to use pass your closure to the baz param

class Boo {
    let world = "world"
    func boo() {
        foo("hello") { (something) -> Int in
            print(world)
            return 100
        }
    }
}

Or, again, you can totally omit the baz param.

class Boo {
    let world = "world"
    func boo() {
        foo("hello")
    }
}