swiftescapingclosures

Swift @escaping and Completion Handler


I am trying to understand 'Closure' of Swift more precisely.

But @escaping and Completion Handler are too difficult to understand

I searched many Swift postings and official documents, but I felt it was still not enough.

This is the code example of official documents

var completionHandlers: [()->Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping ()->Void){
    completionHandlers.append(completionHandler)
}

func someFunctionWithNoneescapingClosure(closure: ()->Void){
    closure()
}

class SomeClass{
    var x:Int = 10
    func doSomething(){
        someFunctionWithEscapingClosure {
            self.x = 100
            //not excute yet
        }
        someFunctionWithNoneescapingClosure {
            x = 200
        }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)

completionHandlers.first?() 
print(instance.x)

I heard that there are two ways and reasons using @escaping

First is for storing a closure, second is for Async operating purposes.

The following are my questions:

First, if doSomething executes then someFunctionWithEscapingClosure will executing with closure parameter and that closure will be saved in global variable array.

I think that closure is {self.x = 100}

How self in {self.x = 100} that saved in global variable completionHandlers can connect to instance that object of SomeClass ?

Second, I understanding someFunctionWithEscapingClosure like this.

To store local variable closure completionHandler to global variable 'completionHandlerswe using@escaping` keyword!

without @escaping keyword someFunctionWithEscapingClosure returns, local variable completionHandler will remove from memory

@escaping is keep that closure in the memory

Is this right?

Lastly, I just wonder about the existence of this grammar.

Maybe this is a very rudimentary question.

If we want some function to execute after some specific function. Why don't we just call some function after a specific function call?

What are the differences between using the above pattern and using an escaping callback function?


Solution

  • Swift Completion Handler Escaping & Non-Escaping:

    Assume the user is updating an app while using it. You want to notify the user when it is done. Maybe you want to pop up a message that says “Congratulations, now you may fully enjoy!”

    So how do you run a block of code only after the download has been completed? Further, how do you animate certain objects only after a view controller has been moved to the next?

    Based on my experience completion handlers can be summarized as:

    "Do stuff when things have been done"

    Bob’s post provides clarity about completion handlers (from a developer viewpoint it defines what we need to know).

    @escaping closures:

    When one passes a closure as a function parameter, it is executed after the function’s body and then control is returned to the caller. When the function ends, the scope of the passed closure exists (in memory) until the closure gets executed.

    There are several ways to use an escaping closure from the containing function:

    When you try to use the closure in these scenarios the Swift compiler produces the error:

    error screenshot

    For more details about this topic refer to this post on Medium.

    To reiterate:

    1. Escaping Closure: A closure that’s called after the function it was passed to returns. In other words, it outlives the function it was passed to.
    2. Non-escaping closure: A closure that’s called within the function it was passed into, i.e. before it returns.