How Does One Make an Optional Closure in Swift

How does one make an optional closure in swift?

You should enclose the optional closure in parentheses. This will properly scope the ? operator.

func then(onFulfilled: ()->(), onReject: (()->())?){       
if let callableRjector = onReject {
// do stuff!
}
}

Optional closures in Swift 4

Distinguish between single-tuple and multiple-argument function types

// Declare closure
var checksPerformed: (() -> ())? // Declaration

// Call when needed
checksPerformed?()

//Only executes when checksPerformed is called
checksPerformed = {
// do stuff here
}

Optional closures in swift 5

I'm assuming when you say "how to write an optional closure" you mean "how to call an optional closure", because you've written the closure parameter just fine, but you're just not calling it correctly.

To call an optional closure, you need to unwrap it first. Either:

completion?()

or:

if let unwrappedCompletion = completion {
unwrappedCompletion()
}

Passing optional closure to the View

Change your variable let to var.

var action: (() -> Void)? = nil

Swift optional escaping closure parameter

There is a SR-2552 reporting that @escaping is not recognizing function type alias. that's why the error @escaping attribute only applies to function types. you can workaround by expanding the function type in the function signature:

typealias Action = () -> ()

var action: Action? = { }

func doStuff(stuff: String, completion: (@escaping ()->())?) {
print(stuff)
action = completion
completion?()
}

func doStuffAgain() {
print("again")
action?()
}

doStuff(stuff: "do stuff") {
print("swift 3!")
}

doStuffAgain()

EDIT 1::

I was actually under a xcode 8 beta version where the bug SR-2552 was not resolved yet. fixing that bug, introduced a new one(the one you're facing) that is still open. see SR-2444.

The workaround @Michael Ilseman pointed as a temporary solution is remove the @escaping attribute from optional function type, that keep the function as escaping.

func doStuff(stuff: String, completion: Action?) {...}

EDIT 2::

The SR-2444 has been closed stating explicitly that closures in parameters positions are not escaping and need them to be marked with @escaping to make them escaping, but the optional parameters are implicitly escaping, since ((Int)->())? is a synonyms of Optional<(Int)->()>, optional closures are escaping.

Swift optional escaping closure

Clarification:

For understanding the case, implementing the following code would be useful:

typealias completion = () -> ()

enum CompletionHandler {
case success
case failure

static var handler: completion {
get { return { } }
set { }
}
}

func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}

At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:

error: assigning non-escaping
parameter 'handlerParameter' to an @escaping closure

let chObject = CompletionHandler.handler = handlerParameter

with a note that:

note: parameter 'handlerParameter' is implicitly non-escaping func
doSomething(handlerParameter: completion) {

Why is that? the assumption is that the code snippet has nothing to do with the @escaping...

Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum, struct or class by default.

As a reference, there are bugs reported related to this issue:

  • Optional closure type is always considered @escaping.
  • @escaping failing on optional blocks.

Although they might not 100% related to this case, the assignee comments are clearly describe the case:

First comment:

The actual issue here is that optional closures are implicitly
@escaping right now.

Second comment:

That is unfortunately the case for Swift 3. Here are the semantics for
escaping in Swift 3:

1) Closures in function parameter position are
non-escaping by default

2) All other closures are escaping

Thus, all generic type argument closures, such as Array and Optional, are escaping.

Obviously, Optional is enum.

Also -as mentioned above-, the same behavior would be applicable for the classes and structs:

Class Case:

typealias completion = () -> ()

class CompletionHandler {
var handler: () -> ()

init(handler: () -> ()) {
self.handler = handler
}
}

func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}

Struct Case:

typealias completion = () -> ()

struct CompletionHandler {
var handler: completion
}

func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}

The two above code snippets would leads to the same output (compile-time error).

For fixing the case, you would need to let the function signature to be:

func doSomething( handlerParameter: @escaping completion)


Back to the Main Question:

Since you are expecting that you have to let the completion:(()->())? to be escaped, that would automatically done -as described above-.

optional closure property in Swift

I believe you just need to wrap the closure type in parenthesis, like so:

var respondToButton:((sender: UIButton) -> Bool)?

Alternatively if this is a closure type you're going to use often you can create a typealias to make it more readable:

typealias buttonResponder = (sender: UIButton) -> Bool

then in your class:

var respondToButton:buttonResponder?


Related Topics



Leave a reply



Submit