How to use weak self in Swift | Continued Learning #18
Summary
TLDRIn this educational video, Nick from Swiftly Thinking dives into the concept of 'weak self' in Swift programming, a crucial topic often overlooked in beginner courses. He explains the importance of understanding Automatic Reference Counting (ARC) for efficient app development. Through a practical example, Nick illustrates how to avoid creating strong references that can lead to memory issues, especially during asynchronous tasks like internet data downloads. He emphasizes the use of 'weak self' to allow classes to de-initialize properly, ensuring app efficiency and performance.
Takeaways
- 📚 The video is an educational resource on 'Swiftly Thinking', focusing on Swift and SwiftUI development.
- 🔑 The main topic of the video is 'weak self', explaining its importance in Swift development, especially with asynchronous tasks.
- 🤔 The concept of 'weak self' is often overlooked in beginner courses and can lead to memory inefficiencies if not properly understood.
- 🔄 'Automatic Reference Counting (ARC)' is fundamental to understanding 'weak self', as it manages the lifetime of objects in Swift.
- 📉 Keeping the reference count low improves app efficiency and performance by allowing de-initialization of objects not in use.
- 🔗 'Weak self' is used to prevent strong reference cycles, which can occur when asynchronous tasks are performed and the object should not stay alive.
- 👍 The presenter, Nick, emphasizes the importance of 'weak self' for efficient app development and to avoid memory leaks.
- 🛠️ The video provides a practical example of creating a navigation view with two screens to demonstrate the use of 'weak self'.
- 📝 It illustrates the use of 'weak self' in the context of a ViewModel to handle data asynchronously without retaining a strong reference to the view.
- ⏱️ A simulated long task is used to show how 'weak self' allows a view to de-initialize even when an asynchronous task is pending.
- 🔑 The video concludes with the advice to use 'weak self' in asynchronous operations to maintain app efficiency and prevent slowdowns.
Q & A
What is the main topic of the video?
-The main topic of the video is explaining the concept of 'weak self' in the context of Swift programming, particularly when dealing with asynchronous tasks and automatic reference counting (ARC).
Why is understanding ARC important for app development?
-Understanding ARC is important for app development because it helps manage memory efficiently, making the app run faster and more smoothly by keeping the reference count of objects as low as possible.
What is a strong reference in the context of ARC?
-A strong reference in ARC is a regular reference to an object that keeps the object alive in memory. It prevents the object from being de-initialized until the reference is removed or the object is no longer needed.
What is the purpose of using 'weak self' in Swift?
-The purpose of using 'weak self' in Swift is to create a weak reference to the current class or object, allowing it to be de-initialized when it's no longer in use, which helps prevent memory leaks and improve app efficiency.
Why is 'weak self' particularly important when downloading data from the internet?
-'Weak self' is particularly important when downloading data from the internet because it ensures that the memory associated with the current screen or view can be freed up if the user navigates away while the download is in progress.
What does the term 'de-initialize' mean in the context of this video?
-In the context of this video, 'de-initialize' refers to the process where an object or screen is removed from memory when it's no longer needed or when the user navigates away from it.
How does the video demonstrate the use of 'weak self'?
-The video demonstrates the use of 'weak self' by creating a simple app with two screens and a view model, then simulating a long-running task to show how 'weak self' allows the app to de-initialize objects that are no longer in use.
What is the potential issue with using 'self.' instead of 'weak self' in asynchronous tasks?
-The potential issue with using 'self.' instead of 'weak self' in asynchronous tasks is that it creates a strong reference to the current class or object, preventing it from being de-initialized until the task is completed, which can lead to increased memory usage and decreased app performance.
How does the video simulate a long-running task?
-The video simulates a long-running task by using a delay within a DispatchQueue.main.async block, setting it to 500 seconds, to mimic the time it might take to download data from the internet.
What is the significance of the 'count' variable in the app's user interface?
-The 'count' variable in the app's user interface is used to track the number of view models that have been initialized. It helps visualize the impact of using 'weak self' versus 'self.' on the number of objects kept in memory.
Outlines
📚 Introduction to 'Weak Self' in Swift
Nick, the host of 'Swiftly Thinking', introduces the concept of 'weak self' in Swift programming. He emphasizes its importance, especially for beginners, which is often overlooked in learning materials. The video aims to clarify what 'weak self' means and its role in app development. The explanation begins with Automatic Reference Counting (ARC), discussing how it manages object references for efficiency. Nick illustrates the issue of inadvertently creating strong references that prevent screen de-initialization, which 'weak self' helps to resolve. The tutorial is set to prepare viewers for upcoming videos on downloading data from the internet, where understanding 'weak self' is crucial.
🛠 Building a Navigation View with 'Weak Self'
The tutorial proceeds to a practical demonstration within Xcode, creating a simple navigation view with two screens. Nick guides viewers through setting up a 'SwiftUI View' and a 'ViewModel' for the second screen, which conforms to the 'ObservableObject' protocol. He explains the significance of the 'init' and 'deinit' methods in the lifecycle of a view. The example serves to show how 'weak self' can be implemented in a real-world scenario, with a focus on the ViewModel's role in handling data asynchronously.
🔄 Simulating Asynchronous Tasks and 'Weak Self'
Nick simulates a long-running asynchronous task using a delay to mimic downloading data from the internet. He demonstrates the problem of creating strong references to 'self' within closures, which can prevent the de-initialization of a view. This results in increased memory usage and potential performance issues. The example shows how the count of initialized views increases without de-initializing, highlighting the inefficiency caused by not using 'weak self'.
🔑 Solving Memory Issues with 'Weak Self'
The solution to the memory issue is presented by modifying the closure to use 'weak self' instead of 'self'. This change allows the system to de-initialize the view even when asynchronous tasks are running, preventing memory leaks and improving app performance. Nick shows how this adjustment keeps the count of initialized views stable, even when navigating back and forth between screens, demonstrating the efficiency of using 'weak self' in asynchronous operations.
🎓 Conclusion on the Importance of 'Weak Self'
In conclusion, Nick wraps up the tutorial by reiterating the importance of using 'weak self' in Swift development, especially when dealing with asynchronous tasks like internet data downloads. He emphasizes that understanding and correctly implementing 'weak self' can lead to more efficient and professional code, preventing unnecessary memory usage and keeping the app running smoothly.
Mindmap
Keywords
💡Weak Self
💡Automatic Reference Counting (ARC)
💡Strong Reference
💡De-initialize
💡Swift UI
💡ViewModel
💡Closure
💡Dispatch Queue
💡Navigation View
💡Observable Object
💡User Defaults
Highlights
Introduction to 'weak self' concept in Swift programming.
Explanation of why 'weak self' is crucial for efficient app development.
Overview of Automatic Reference Counting (ARC) in Swift.
Importance of minimizing reference count for app efficiency.
Discussion on the unintended creation of strong references in app development.
Solution to strong reference issues by using 'weak self'.
Upcoming tutorial on downloading data from the internet and its relation to 'weak self'.
Creating a 'Weak Self Boot Camp' project in Xcode.
Explanation of Navigation View and its setup in Swift.
Demonstration of creating a simple two-screen navigation app.
Introduction of ViewModel and its role in app architecture.
Explanation of 'init' and 'dinit' functions in ViewModel.
Integration of ViewModel with the 'Second View' in the app.
Simulating the impact of asynchronous tasks on app memory.
Illustration of memory inefficiency with strong references during async tasks.
Implementation of 'weak self' to allow de-initialization during long tasks.
Demonstration of efficient memory management with 'weak self'.
Highlighting the professional use of 'weak self' in asynchronous operations.
Conclusion on the importance of 'weak self' for efficient and professional app development.
Transcripts
[Music]
what's up everyone
welcome back i'm nick this channel is
swiftly thinking where we cover all
things
swift and swift ui related and in this
exciting video
we're going to look at weak self we're
going to learn
what exactly weak self means and why we
use it
and i'm super excited to share this
because this is something that i
wish someone had stressed and explained
to me more
when i was learning app development it's
often overlooked as people start to
learn app development
and a lot of beginner courses don't even
touch on it but it is
very important in order to get into
excel we first have to understand
automatic reference counting and you can
google this
arc automatic reference counting and
apple probably has a bunch of articles
on exactly what it is
but basically every time you make an
object or a screen
the system is holding a reference to
that object
so reference counting by itself is
pretty simple
but as developers we want to keep this
count as low as possible
because it makes our app more efficient
and faster and often times in your app
when users are moving around the app
behind the scenes
the app is actually de-initializing
screens and views
that the user is no longer using so this
is efficient so if they go to the screen
and then
press it back that screen might get
de-initialized so any objects that were
created on that screen
would then be removed from our account
and this is great
but sometimes in our app we end up
writing code
that doesn't allow that screen to
de-initialize when we actually want it
to
and you might not even realize you're
doing this but you basically are
creating a
strong reference to that screen or that
object
and the solution is to basically create
a weak reference instead of a strong
reference
and that's kind of what weak self is now
i'm covering it right now because in the
next bunch of videos
we're going to start downloading data
from the internet because
when we have these functions that are
going to the internet and then coming
back
it becomes super important to understand
these strong and weak references
and you're probably going to want to use
a weak self a lot of times
so i hope this doesn't get too confusing
for some of you guys leave a comment
below if you are still confused
but i think the example we're going
gonna go through uh really helps to
explain it
all right and if you are enjoying this
content please don't forget to hit the
like button and the subscribe button to
stay up to date with all of these videos
and this playlist
all right welcome back everyone i'm back
in xcode as always
in this video we're looking at the week
self call
and we're going to do that in a new file
so let's right click on the navigator
create a new file
it's going to be a swift ui view and
let's call this week
self boot camp go ahead and click create
once you're inside click resume on the
canvas
and this again is something that i wish
someone had talked to me a little more
about when i was learning to code
because
because this is very important when you
actually make applications
and i don't think a lot of beginners
even think about
something like this so some of what
we're doing here is a little bit
abstract
so i try to find the simplest way to
explain this to you guys
and what we're going to do is create a
navigation view on our screen
we'll add a navigation view open the
brackets inside the navigation view
is going to be a very simple navigation
link
open the parentheses we're going to use
the uh let's use the
string protocol and destination the
title will say
maybe navigate nothing important
here and then the destination we're
going to change in a second
but let's just make it a text right now
with a blank string
and let's create a second screen here so
underneath this struct
i'm going to create a new struct let's
call it weak
self second screen
it will conform to view just like our
main view
and every view needs a body and we'll
open the brackets
the body here is gonna be very simple
just gonna be a text that says second
view let's give it a font of large title
and a foreground color of
red let's add this into our destination
so we'll do weak
self second screen
let's click resume in the canvas just to
make sure it all works
let's also add a navigation title here
screen one all right so on screen one
we can press play here on the sim
on the canvas click navigate and it
should bring us to the second view
alright so this is a very simple app if
you're confused at this point
you should probably go check out some
more beginner videos on my
youtube channel because this should not
be anything new to you guys this should
be very simple
we have two screens in a navigation view
we can navigate
we can press back and here we are all
right
this second screen is going to have a
view model so we're going to create
that now we'll do it underneath this
struct we'll say
class let's call it weak
self second screen
view model i know it's really long to
type here
the name doesn't really matter let's
make it conform to observable object as
always
open the brackets and we're going to
create a at published in here
this will be a var we'll call it data
and it'll be of type a string we're
going to make it optional with a
question mark
we're going to set it equal to nil for
now
inside this view model we're then going
to create an init
open and close parentheses open the
brackets in this init
let's print out initialize now
and we're going to call function to get
data so let's create a func
get data open close parenthesis open the
brackets
from in the init we'll call get data so
as soon as it loads
and in get data we're just going to call
uh data equals new data
before we leave here let's also create a
d init
which is pretty much the opposite of an
init this happens when the screen gets
initialized
this happens when the screen gets
de-initialized and let's just print
here we'll print d initialize
now all right
the last thing i actually want to do is
put this data this string
onto the second screen so on the second
screen
let's first add the view model we'll do
in at
state object var vm for view model
equals the weak self second screen view
model
and let's hold the command button click
on this text
let's embed it in a v stack and below
the second view text we'll just add
we'll say if let data
equals vm.data open brackets
so if this is data so if this is
actually a value and not equal to nil
we'll then add a text here and we'll put
in the data
all right if i click resume on the
canvas let's first check that this data
is loading in let's click navigate
and it says new data perfect and now
let's run this on a simulator so i'm
going to take this
so i'm going to take the first screen
here which is our weak self boot camp
i'm going to jump into our app.swift
file i'm going to make this the first
file in our app
make sure we're on an iphone 12 you can
do it on whatever simulator you would
like i'm going to do an iphone 12
and let's run it on a simulator
i'm going to jump back into our file
here as well i'm going to close the
canvas
and you can ignore some of these
warnings that that are coming through
right now
it's just some swift ui uh stuff that
apple's probably working to get rid of
and i'm gonna
and i'm gonna actually just scroll down
here and
just press enter a bunch of times to
break this out
but when i click navigate it should
initialize a view model so let's click
navigate
initialize now i'm gonna go back and i'm
gonna press
navigate one more time and we clicked it
the second time it initialized the new
one and de-initialized the first one
and i'm going to press back and forward
and back and forward and you can see
here every time we go to this screen
it is de-initializing one and
initializing a new one
okay so let's create a quick little
variable
on our screen just to track how many are
initialized at a time
so we're going to do a quick kind of
little hack here we're just going to
create a user default
so on our first screen here
let's do it um let's do it on top of the
navigation view so on
at the bottom of the navigation view i'm
going to add in dot overlay
and let's add a text for the number one
for a second
let's see if we see it let's go to
background of color.green
uh sorry let's open up the canvas so we
can see what we're doing
all right we can see our number here
let's give it a font of
large title
let's add some padding and let's give
this overlay a
we'll use the comma and we'll add
alignment of maybe
top trailing
just so it's on the top right here at
all times let's give that background a
corner radius
10. all right so this is how many are
initialized right now
so this number one let's make it track
and a user default and i covered user
defaults in another video so i'm not
going to go over how they work
in this one you can check out my other
videos on app storage
but let's create an app storage we're
going to use a key here
and this will be uh let's just call it
count
this will be a var and we'll we'll call
it count
and this will be of type int and it will
be optional in case it's not set yet
and we're just going to put this count
into the text here so we'll do a
backslash open close parenthesis
put the count and because it's optional
if there is none let's do two question
marks and have it be
zero if i click resume
it should
work we got zero and now
every time we initialize very simply
let's first get the current counts we'll
say let
currentcount equals
userdefaults.standard.com
int integer for key and the key is count
remember this key is the same as the key
that we just did up here
and remember we're using user defaults
down here because we are not in a view
but because we're in a view we can use
app storage up here
i covered this all in the app storage
video so i'm not going to cover that
again
right now but this will be the current
count and then we're just going to set
userdefault.standard.com
set and we're gonna look for the integer
and we're gonna set
current count plus uh
one and this will of course be four key
count and when we go to d initialize
let's copy these two lines
and we're just going to do minus one on
the d initialize
okay so every time we initialize we add
one every time we de-initialize well
minus one so these should be equaling
each other out
and the last thing i want to do here is
actually
on that first view every time we load
the app
let's just start the count back at zero
so we'll do init
and here we'll just set the count equal
to zero
all right let's run the app on a
simulator quick
our count is zero and when i go to
navigate
count goes up to one and if i go back
we can see our prints are coming through
our initialize now if i go to do another
one
we initialize the new one but we also
de-initialize the old one
so the count is still one if i go back
and i go forward and i go back and i go
forward i can do this a whole bunch of
times
and the count is always one so this is
great and this is efficient right
because
if this count kept going up it would be
saving the memory of all of those old
screens
but right now our count remains at one
and this is perfect
the problem comes into play here when
you are running asynchronous tasks
so right now this is just happening
immediately when we call getdata and if
everything is working fine
and we're all happy so if you watch my
last video
we were going on the background thread
we were using a dispatch
queue.global.async
and when we put our call into that call
we got this error message that the
reference to data required explicit
of self and to fix it we went self
period
and this was creating a strong reference
to this class
and when you're doing this creating a
strong reference basically what you're
telling the system
is that while these tasks are running
this
self so this class absolutely needs to
stay
alive because we need that self
when we come back and right now this is
a very
quick task so it wouldn't actually be a
problem
but if you were downloading like a lot
of data from the internet
the code in this async task might take a
couple seconds it could take like 10
seconds
and during that time the user could be
doing something on the app
like maybe pressing the back button and
by the time the call comes back
you might not actually need this self to
be alive because
maybe the user's already gone they're on
a different screen they don't need this
data anymore
to so to simulate a very long task we're
going to use dispatch
q dot main dot async after
this just creates a delay and we'll do
dot now
plus let's do something absurd like
maybe
500 seconds and then we're going to
press
enter on here and we're gonna take our
code and put it in here
we're gonna get rid of this first call
and basically what we're simulating here
is a very long
uh background task so this task will
take
500 seconds that's a very long time
and when you're downloading data from
the internet it's not going to take 500
seconds
but it will take some time and that's
kind of what we're simulating with this
line of code here
so after 500 seconds the data should
then update
so let's click play on the simulator one
more time
let's we're at zero let's navigate to
that second screen
and it goes to one so we're looking good
and now we're gonna go
back and we go to navigate again it goes
to
two we haven't seen it go to two before
and if we look at our printouts the
initialize was called twice
but d initialize was never called and
the reason
the d initialize was never called is
because we had this
strong reference to self here and when
we had the strong reference to self we
told the code
that that class could not be
de-initialized
until this closure completes so after
this 500 seconds
this will then call this will then be
complete
and then it will de-initialize but until
this 500 second completes
this self will always stay alive in our
code
so for some things that could be good if
we absolutely needed this line of code
to happen
but a lot of times in your app like what
we just did
within that time frame that 500 seconds
the user navigated away they went to
another screen
and so once they did that we didn't
really need to update that original
screen that they were on right
because they're gone they've moved on
they're doing other things in the app
so the fact that we keep this alive is
actually not efficient
and we can see here that if i keep on
navigating
back and forth our count is going to
keep going up
because we're creating all these strong
references
and what's happening behind the scenes
here in the second view we're creating
these view models
and right now there are eight of these
view models
alive in the background of our app
and the fact that we're only on the
screen here on one of them
just proves that this is not efficient
because we now have eight classes in the
background
and we only really need one right we
only need the one that we're on right
now we're never going to get back to
that old screen
so you could imagine that if you created
these strong references all around your
application when you're using this
self dot you're going to get a ton of
objects all around your app
that are alive that don't need to be
alive and when you have all this extra
stuff in your app it is just going to
basically weigh down the app and it
could slow things down
so as the developer this is very
important because this could definitely
slow down your app
so the solution here is basically
instead of calling itself with this
strong reference
which means we absolutely need this
class to stay alive
we could instead add a square bracket
and say weak self and then add the word
in and this weak self basically just
makes this self instead of being a
strong reference
it turns into a weak reference and we're
gonna get a quick error message here
that it is now optional so we can fix it
with the question mark
and basically this code is the exact
same as we had
except self is now optional so we still
have
reference to this data that we can
update but we're telling the code here
that
we don't absolutely need this class to
stay alive
so if this class for whatever reason
gets de-initialized
it's okay and we can just ignore
whatever
these calls are so if i run my app one
more time
and i start clicking forward and back
you'll see that the
you'll see that the number stays at one
again because even though this call
didn't come back
this reference to self was weak it
wasn't strong
so because it was weak we allowed it to
de-initialize
and we got our de-initialized calls back
here so generally speaking in your app
when you have these long tasks that
you're like downloading data for the
user
it's very important to add this weak
self
because if you're downloading data for
the second screen
and then the user goes away to another
screen
you don't really need that first screen
to stay alive anymore
and if you kept that screen alive it
would stay in the memory it would start
to slow down your application
and it just wouldn't be very efficient
alright guys i hope that wasn't too
confusing
um basically the bottom line here is by
using weak self we can make references
to classes and to self optional
so that we're telling xcode it's okay if
this class de-initializes because if we
have a strong reference
it's telling xcode that we absolutely
need the class to stay alive
and in that scenario you would run into
situations where this number keeps going
up
and you can imagine in your app if you
had tons of calls all over your app
and all these extra classes and objects
were staying in the memory
it could definitely weigh down your app
and slow things down
so to be professional efficient expert
developers
we use weak self a lot of the times when
we're doing things
that are asynchronous tasks such as
downloading data from the internet
alright guys i hope you enjoyed this
video uh
as always i'm nick this is swiffle
thinking
and i'll see you in the next video
Voir Plus de Vidéos Connexes
How to use escaping closures in Swift | Continued Learning #20
SMART POINTERS in C++ (std::unique_ptr, std::shared_ptr, std::weak_ptr)
Life Cycle & Reference Counting | Godot GDScript Tutorial | Ep 1.2
Variables in C++
Testing Entity Framework Core Correctly in .NET
Python OOP Tutorial 1: Classes and Instances
5.0 / 5 (0 votes)