How to use escaping closures in Swift | Continued Learning #20
Summary
TLDRIn this informative video by Swiffle Thinking, Nick dives into the concept of closures in Swift, with a focus on escaping closures. He explains the difference between synchronous and asynchronous code, demonstrating how regular functions work with immediate returns versus the delayed execution of asynchronous tasks. Nick illustrates the use of escaping closures to handle data retrieval from a database or the internet, showcasing how to implement them in Swift UI with practical examples. The video is designed to clarify a potentially confusing topic, making it accessible for developers new to asynchronous programming.
Takeaways
- 📚 The video is an educational resource on Swift and Swift UI, focusing on closures and specifically escaping closures.
- 🔄 Nick, the presenter, explains the transition from synchronous to asynchronous code, which is necessary for tasks like downloading data from the internet.
- 🕊️ Synchronous code executes line by line immediately, whereas asynchronous code involves waiting for operations like data retrieval to complete.
- 🔑 Escaping closures are introduced as a solution to handle asynchronous code, allowing a function to be called after an operation completes.
- 🛠️ The script demonstrates building up to escaping closures by first creating a simple ViewModel and View in a Swift UI project.
- 📝 A ViewModel with an observable object pattern is used to bind data to the UI, starting with a simple 'text' variable.
- 🔍 The presenter illustrates the concept of closures by adding a 'get data' function that simulates downloading data asynchronously.
- 🔄 An example of a non-escaping closure is shown, which leads to the introduction of the '@escaping' keyword to handle the delay in asynchronous operations.
- 🔒 The use of 'self.' is explained to maintain a strong reference to the class within the closure to prevent deinitialization before the closure executes.
- 🔓 The video also covers using 'weak self?' to allow the class to be deinitialized if not needed, addressing potential memory management issues.
- ✨ The presenter concludes by showing how to improve code readability with struct models and type aliases for completion handlers in closures.
Q & A
What is the main topic of the video?
-The main topic of the video is about closures in Swift, with a focus on escaping closures, which are used in asynchronous code.
What is the difference between synchronous and asynchronous code as explained in the video?
-Synchronous code runs from top to bottom immediately and then executes, allowing functions to return immediately. Asynchronous code, on the other hand, involves operations that do not complete immediately, such as downloading data from the internet, and requires special handling with escaping closures.
What is an escaping closure in Swift?
-An escaping closure in Swift is a closure that is called after the function in which it is defined returns. It allows the function to handle asynchronous code by executing the closure at a later time, such as after data has been fetched from a database or the internet.
Why are escaping closures necessary when downloading data from the internet?
-Escaping closures are necessary because the data does not return immediately. They enable the function to perform actions after the data has been received, even if that happens after the function has returned.
What is the purpose of the 'completion handler' in the context of the video?
-The completion handler is a parameter of a function that is a closure itself. It is called when the asynchronous task, such as data downloading, is completed, allowing the code to execute subsequent actions with the returned data.
How does the video demonstrate the transition from synchronous to asynchronous code?
-The video demonstrates this by initially showing a simple synchronous function that returns a string immediately. It then modifies the function to simulate an asynchronous task with a delay, which requires the use of an escaping closure to handle the delayed return of data.
What is the issue with using regular returns in asynchronous functions?
-Regular returns cannot be used in asynchronous functions because they expect to return immediately, which is not possible when the operation involves a delay or is waiting for external data.
Why is 'self' used with a dot in front of a property when using an escaping closure?
-Using 'self.' before a property within an escaping closure ensures that the instance of the class remains alive until the closure is executed, as it creates a strong reference to the class instance.
What alternative to using 'self.' is suggested in the video to avoid potential issues with keeping the class instance alive?
-The video suggests using 'weak self' to make the reference to the class instance optional and allow the class to be de-initialized if necessary, thus avoiding potential memory management issues.
How does the video simplify the code when using escaping closures?
-The video simplifies the code by introducing a 'download result' struct to encapsulate the data being returned, and by using a type alias called 'download completion' to represent the completion handler, making the code cleaner and more readable.
Outlines
📚 Introduction to Swift Closures and Asynchronous Code
Nick introduces the topic of closures in Swift, specifically focusing on escaping closures. He explains that while most functions they've covered so far have synchronous return types, upcoming lessons will involve asynchronous code for downloading data from the internet. Nick outlines the difference between synchronous and asynchronous code, emphasizing the need for escaping closures to handle functions that return data after a delay, such as from a database. He promises to guide viewers through the concept, which is crucial for building production applications.
🔄 Understanding Synchronous vs. Asynchronous Code
The paragraph delves into the specifics of synchronous code execution, which is immediate and line-by-line, versus asynchronous code, which involves delays and does not execute immediately. Nick demonstrates this with a simple 'downloadData' function that simulates a database call with a two-second delay. He points out the limitations of regular return statements in asynchronous functions and introduces the concept of a completion handler—a closure used to handle the result of an asynchronous task.
📝 Implementing a Completion Handler in Swift
Nick shows how to implement a completion handler within a function that simulates asynchronous data retrieval. He modifies the 'downloadData2' function to accept a completion handler as a parameter and explains how this allows the function to return data after a delay. He also discusses the error that arises when trying to use a non-escaping closure in an asynchronous context and how to resolve it by using 'self' to maintain a strong reference to the class.
🔑 Using Escaping Closures to Manage Asynchronous Tasks
The discussion moves to escaping closures, which are closures that the called function may hold onto beyond the time it returns. Nick demonstrates how to mark a closure as 'escaping' and how this allows for the delayed execution of code. He also addresses the issue of maintaining a strong reference to 'self' and introduces 'weak self' as a solution to prevent potential memory management issues.
🛠 Refactoring Code for Readability and Efficiency
Nick refactors the code to improve readability and efficiency. He creates a 'DownloadResult' struct to encapsulate the data being returned from the asynchronous function, allowing for the potential return of multiple data points in the future. He then demonstrates the use of a type alias, 'DownloadCompletion', to simplify the signature of the completion handler, making the code cleaner and more maintainable.
🎓 Conclusion and Future Learning
In the final paragraph, Nick concludes the lesson on escaping closures, affirming that viewers are now equipped with the knowledge to use them effectively. He hints at further lessons that will cover downloading data from the internet and integrating it into apps, encouraging viewers to stay tuned for more advanced topics in the Swift programming language.
Mindmap
Keywords
💡Swift
💡Swift UI
💡Closures
💡Escaping Closures
💡Asynchronous Code
💡ViewModel
💡Observable Objects
💡Dispatch Queue
💡Completion Handler
💡Type Alias
💡Weak Self
Highlights
Introduction to the concept of closures and specifically escaping closures in Swift.
Explanation of synchronous code and its limitations when dealing with asynchronous tasks like downloading data from the internet.
The necessity of handling asynchronous code with escaping closures in Swift for tasks that do not return immediately.
Creating a function within a function to manage asynchronous operations, such as data retrieval from a database.
Demonstration of a simple ViewModel setup with an ObservableObject to connect with a SwiftUI view.
Use of an onTap gesture to trigger a function that simulates data download in a synchronous manner.
Transitioning from synchronous to asynchronous code by introducing a delay to simulate database access.
Introduction of the completion handler as a parameter within a function to manage asynchronous results.
Error handling when using non-escaping closures and the need for explicit self usage to maintain class instance during asynchronous tasks.
The use of weak self to prevent strong reference cycles while using asynchronous closures.
Refactoring the code to improve readability and maintainability by using a struct for the returned data.
Utilization of a type alias to simplify the completion handler syntax and improve code efficiency.
Practical demonstration of using escaping closures to update UI elements after asynchronous data retrieval.
Discussion on the commonality of using escaping closures for returning data and returning void in production applications.
Providing alternative approaches to customize closures for different return types and values.
Conclusion summarizing the importance of understanding and using escaping closures in Swift for asynchronous programming.
Transcripts
welcome back
everyone i'm nick this channel is
swiffle thinking where we cover all
things
swift and swift ui related and in this
exciting video we're going to look at
closures
and even more specific we're going to
look at escaping closures
now if you've been following my courses
so far almost all the functions that
we've created either didn't return
anything
or had a regular return type and that's
been working perfectly
but in the next couple of videos we're
gonna start downloading data from the
internet
and when we do that we have to use
asynchronous code
and to explain that really quickly when
we have synchronous code
it runs from top to bottom immediately
and then executes so if we have a
regular function
we will write the function it will run
all those lines in our code and then it
will return as soon as it gets to the
bottom
so those functions basically can return
immediately
but when we are going to a database to
download data from our internet
we're going to create functions to go
get that data but that data is not going
to come back immediately
it's going to take a couple seconds to
go to the server get that data
bring it back to our app so we can't
just
immediately return out of this function
and instead of
immediately returning we need to handle
this asynchronous code
and we do that in swift with escaping
closures
so basically what we end up doing is
creating a function and then within that
function
we are passing another function as a
parameter into the first function and
this way we can call that second
function
when our code comes back from the
database and when we want it to actually
execute
so this is something that sounds
confusing and actually could be
confusing
if you've never dealt with asynchronous
code before so i hope this video helps
someone out there who is struggling with
this
because this is used all the time in
production applications and something
you
definitely will need to know all right
and that's enough of me talking
let's jump into the code and we're going
to build our way up to this escape
enclosure so you guys can fully
understand
what's going on all right
welcome back everyone we're back in our
xcode project with another
fun video today let's right click on the
navigator create a new file for the code
we're going to write
and this of course will be a swift ui
view and
let's call this escaping boot camp
go ahead and click create and we're
calling it escaping because in this
video we're going to cover escaping
closures now before we actually get into
escaping closures i want to build up to
them
so you can understand why we are
actually using them
and then i'll show you how to use them
so let's start very simply by creating a
view model
for our view so we'll say class let's
call it
escaping view model
let's make it conform to observable
objects so that we can observe it from
our view
while we're here let's initialize one in
the view
we'll use an at state object
var let's call it vm for viewmodel and
we'll set it equal to an escaping
viewmodel
all right in this view model we're gonna
have a very simple
variable we'll do at published var
we'll call it text and it'll be of type
string and we'll set it equal to
uh hello to start very simple
on the view we're going to connect this
text to the view model text
so we'll say vm dot text
let's just make it font of large title
font weight of
semi and maybe a foreground color of
blue let's click resume on the canvas to
make sure
it is all connected we should see our
hello text here
and in the view model we're going to
create a very basic function we're going
to say func
get data open close parenthesis open the
brackets
and we will call this get data from the
view
so when we tap on this text let's add an
ontap gesture and we'll call vm.getdata
very simple so when we tap it this
function
will run and this function is actually
going to call another function
we'll create another func we'll call it
download data
open close parentheses open the brackets
and we're not going to actually download
data in this video but we're going to
simulate like it does
so for right now let's have this
download data
return a string
so this is the regular return type in
swift where we can immediately return
and it will return us a string so here i
will return
and let's say new data
now from inside get data we can then
call
download data so we can say let new data
equals download data and then we can
just set our text
equal to the new data we could have done
this on one line but i just want to
be very explicit on what we're doing
here
so this should work let's click resume
on the canvas
click play on the live preview and when
we tap on hello
it should change to new data this should
not be anything new to you guys we're
just updating this text variable
and when we have these regular return
functions here
this is something called synchronous
code so basically if we had a whole
bunch of logic in this
function here it would run immediately
line by line by line right so this is
the regular
swift code where we do something line
one runs line two line three line four
line five
and then it will immediately return so
basically as soon as we call download
data it will immediately
return us a string and that's great
whenever you can use this you should use
this but there are times when this is
not going to work
so below this function let's create a
new func we'll call it download
data two open close parenthesis open the
brackets
let's have this return a string for a
second and let's also return
new data let's call this download data 2
from our actual code in the get data
and for this function let's pretend like
it's actually going to go to the
database
so obviously we're not going to do all
the code to download from the internet
but what we can do is call a dispatch
queue
dot main dot async after
we can do.now and maybe give it plus two
seconds
and then we can put some code inside so
basically this is a
adding a delay to our code and the delay
is two seconds
so after this is called it will wait two
seconds and then
call the code inside so then i'm going
to cut and
paste my return new data in here
and this is where our problem comes from
because
when we have these regular returns they
want to return
immediately this is synchronous code but
when we add these delays
into our code this is asynchronous this
is not happening immediately this is
happening
at a different point in time so this is
happening two seconds in the future
and when we actually go to start
downloading from the internet
we're going to add lines to download
from the internet but that result isn't
going to come back immediately it's
going to take a couple seconds
to go to the internet get that data and
then come on back
so when we start downloading from the
internet we're going to run into this
problem every time and we can't use
these regular
returns all right so
now let's get into the solution here and
i'm going to put the return data back
and before we use an escape enclosure
we're just going to look at the basics
of a closure so
basically closure is adding a function
as a parameter
into your original function
so instead of returning this string here
i'm going to instead type a parameter
called
completion handler
and this will be of type and we're going
to open the parenthesis using underscore
let's call this data it will be of type
string close the parentheses and then
this function will return void
all right so i'm going to explain this
in a second and then instead of
returning because we don't have that
regular return at the end of our
function here
now we have a completion handler which
is then a function that we can call
by calling completion handler
and then passing in our new data here
before we move forward i first want to
point out that i'm calling this
completion handler
very common people will just call it a
handler or
just completion i'm going to use
completion handler just to be a little
more explicit in this video
and we're getting this error message at
the top here because
when we write our code like this it is
creating this new data function with a
string so for regular download data it
is returning immediately so we can set
up
this variable called new data but when
we have download data too it's not
returning anything immediately so
because it's not returning anything we
can't actually just set up a variable
with this result instead
we are going to call download data2
and then on the completion handler we're
going to press enter
and this string that we're seeing here
is this data
string that we put here and obviously
the string is going to be this new data
so let's call this returned data
and then in this completion block here
we will set
text equal to the returned data
all right so if i resume the canvas and
press play on the live
preview this should work now we can
click hello and it still says new data
and we're using our download
data2 function so basically as soon as
we call this completion handler
it's going to execute this function
and this function is this
this block here
so before we move forward looking at
this this is
kind of ugly to see if you've never seen
it before but think about this just
as a separate function if we were to
create a function
let's let's do funk do something
open close parenthesis open the brackets
and this do something let's pretend
like it had a parameter called data of
type string
all right so this is very similar to
what we have here data of type string
but we have this weird underscore
so when we create functions we can
actually add external and internal
names or labels so right now we just
have one label for data
so in this code we can do print
data okay and if i were to call this
from my code i'll do it up here real
quick i'll say
do something and when we go to call it
we see the word
data as well but we could add an
external name for this data
we can say maybe just four data
and now when i call this from my code
do something externally so outside of
the function
everywhere else this will save for data
and this
is often used to make this more readable
so we'll do something for
data but internally inside this closure
we still reference just data we don't
use four data
inside the closure however when we're
creating this completion handler
we can actually use these external names
here
so instead we just use an underscore and
then if we call to do something
we can see that we have the underscore
and data
so basically we just can't give it an
external name and that's why we have
this underscore
and then lastly we have this return void
and that's what this function is so if
this function wanted to
return a string we could change this to
return string but if this doesn't return
anything like it was
so right here this is actually going to
return a
void swift is just generally
smart enough to know that this function
doesn't return anything so we never
really have to write this in our code
except for when we're using these
completions and now another way to write
this
return void is also return
open close parentheses so void and this
open close parenthesis are basically the
same thing just saying that this
function doesn't return
anything so often when people use these
completion handlers instead of putting
void they will just put open and close
parentheses
and this is a structure you're going to
see a lot as we move forward
so i just wanted to introduce you guys
to that
and now let's take this one step further
so i'm going to
copy this download data to paste it down
here
let's make this download data3
i'm going to change the title the value
i'm going to change the function up here
to
3 and now we have one more problem
because if
in here we tried to add our delay as if
we were going to the database we had our
dispatch queue dot main dot async after
we'll do now plus two seconds and then
we'll put our completion handler
inside so this again is simulating going
to the database
and when we do this we are actually
still going to get an error message
that this escape enclosure captures a
non-escaping parameter
so this now is where our escape
enclosure comes in so all we have to do
to modify this non-escape enclosure
to be escaping is add at scaping
and when we add this at escaping it
makes our code asynchronous which means
it's not going to immediately execute
and return
and that's why we have this delay here
and that's also why we're going to get
this error message that the reference to
this property text
requires explicit use of self so if you
remembered a couple videos
back i covered weak self and the reason
i did that first is because as we start
to download from the internet
we're going to run into these
asynchronous tasks and every time we do
that we're going to get this error
message so the easiest way
to solve this is just just add self dot
and this creates a strong reference to
this class so what's going to happen
here is we're going to call this
download data
but this closure is not going to
immediately execute
this closure will execute whenever we
call it in our code so this completion
handler is going to be called
in two seconds and during
that time between when we called
download data and this closure
there's a chance that the user has
navigated around the app
maybe they did something else and maybe
they went to another screen that
actually doesn't even
need this escaping view model so there's
a chance in our app
that we would have de-initialized this
class
when we create this strong reference to
the class
we're basically telling xcode that we
absolutely need this class
to be alive when we come back into this
closure
so because of that we create this strong
reference but in that video that i did
i think two videos ago i explained why
that's not always
the best solution because if there are
cases when this class should be
de-initialized
this self might be keeping it alive and
that could cause issues in your app and
start to slow down your app
so the solution here is to make self a
weak reference instead of
a strong reference and we do that with
the square brackets
we type weak self and then this self
actually becomes optional by doing this
we are then telling
xcode that it is okay if we want to
de-initialize this class
we don't absolutely need it to be alive
all right so now if i click resume on
the canvas we're using an at escape
enclosure
which we are simulating download from
the database it's going to take two
seconds and then it's going to return
so if i click on hello it should take
two seconds
and then update and now you guys know
how to use the escape enclosure
before i wrap up this video i want to
show you guys two ways to make this
a little bit of code here actually a
little more readable and this is
something that i've seen a lot in
production apps
especially larger code bases so let's
copy this
download data3 let's paste it below
let's make this download data4
and and as we know the data right now is
just of type string
so let's create a model for this
returned data
so outside of the view model i'm in
between
the view model and the struct here i'm
going to create a
struct let's call this let's call this
download result
and we'll open the brackets and this
download result is going to be just like
all of the models we've been setting up
in all of our videos
and of course it's only going to have a
data of type string so we'll say
let data of type string
and now that we have this download
result type we can actually
change out this underscore data
type string and just put in a download
result
and in our completion we we can say let
result
equals download result
we'll put in our data of new data
and then our completion handler we will
just include
the result
all right so going up to our download
data let's delete what we have
let's do download data for
and now we can see that it is a type
download result and i'll click
enter here and i'll put this as returned
result let's make it a
weak self like we just did this will be
self
with a question mark dot text and we'll
set it equal to
the returned result dot data
and you can see that this could be more
efficient
if we had a whole lot of data that we
wanted to return because we could add a
bunch of variables into this download
result
and then we could access them through
here we could say download result
dot and we get all of those data points
that we wanted to
have that we wanted to be returned
so if i click resume on the canvas one
more time
it says hello i click it i wait two
seconds it should still work
and one more step further
i want to show you guys we're gonna copy
this download data for
let's do download data five
this time i'm going to use a type alias
and i cover this in the last video
and this is basically we can create a
new
we can give a name for a type
so i'm going to give this a name of
download completion
and this will be of type
i'm going to take this type here so this
download result with the open close
parenthesis
that returns void i'm going to copy that
and paste that
here so the completion is a download
result
that returns void and i'm going to take
this download completion and
instead of all this code we're just
going to put
download completion
so you can see in this download date of
5 how we went from
this ugliness here which could get very
long if you had a whole bunch of
if you had a whole bunch of variables
that you were returning
we made it shorter with the result then
we made it even better by just making it
a completion and we don't even have this
arrow and void so this
is very efficient coding let's go back
up to
our app and where we have download data
for
the completion block is actually the
exact same so i can just change this to
five i can click resume on the canvas
hello let's click it it'll wait two
seconds and then update
all right guys now you are experts at
using this ad escaping and
there are a bunch of other cool things
that you can do with ad escaping
to make really customized closures for
example
we only had our closures return void you
can actually make them
return other values but this scenario
here where it is
giving us data and returning void is
definitely the most common that i've
seen
and i think this is a pretty solid
starting point
if you've never used these closures
before
i'll zoom out here so you can see the
code but now that we do know this at
escaping
we can actually get into downloading
this data from our internet finally and
putting it into our app
alright guys thank you for watching as
always i'm nick
this is swiffle thinking and i'll see
you in the next video
浏览更多相关视频
How to use weak self in Swift | Continued Learning #18
Asynchronous JavaScript in ~10 Minutes - Callbacks, Promises, and Async/Await
Swift Closures: @escaping Explained
Learn Closures In 7 Minutes
Javascript Promises vs Async Await EXPLAINED (in 5 minutes)
More Closure Examples | JavaScript 🔥 | Lecture 129
5.0 / 5 (0 votes)