In part 1, we have created leak memory in closure. Creating your own leak for research is like saying "don't push me on my own" 🤣
For fun, but in fact when you understand why such a leak is then next time you will not be prone to leaking anymore, right? In this article, we fall for itself in a whole new leak: That's the leak in singleton. Oh, it sounds dangerous 😉 But I bet when I finished reading this article you said "oh how, it's easy to say 😋" OK goat, so squeeze your colleague's ass one and then get to work.
The first is that you need to have a source:
https://github.com/codetoanbug/LeakMemorySamples.git
The code is in branch bai2, and if you don't know what I'm saying, please read the following paragraph:
quotes from the article: https://codetoanbug.com/lap-trinh-ios-trien-khai-mvvm-cho-prject-swiftphan-2/
However, I recommend playing with the Terminal of the MacBook for it pro. Because if you download vegetarian using the browser, you do not see where the source code is :v
The simple terminal is as follows:You typed
the cd command into the source code the previous day you downloaded:cd LeakMemorySampl
e2. Next is to type fetch to get my latest source code about:git fetch
3. Next is you show the entire branch on my repo with the command: git branch -a Here you
will see the following branch:bai1 *bai2 masterExamples
this article, I put all the source into the branch named bai2. You switch to the source code post 2 asfollows: git che
ckout bai2 After branch bai2 is boldly colored, you have already succeeded. And if it doesn't show you're wrong, do it again!
- What is Singleton?
Before we create a leak for it, let's understand what Singleton is? It's a concept in English. But if understood in a pure Vietnamese sense, singleton is a class creation technique that only initiates once. What does that mean? Let's see the following example:
Class AlertViewHandleLogic {
}
I created a class like this and there's absolutely nothing in it. and you open the project, go to the SingletonLeakViewController file:
See it running normally as shown. Next I turned the AlertViewHandleLogic class into a singleton as follows:
- Line 11: I make the init creation function private, that is, do not allow other classes to initiale it anymore.
- Line 12: I created a static shared variable to call the function created at itself, ok it runs.
When creating like this, you build again and go to view in the SingletonLeakViewController file, the result is as follows:
It reports a last-minute error, which translates to a privately protected init function – so you can't call the generated function here. OK, how am I going to call this class?
I called it through the variable. At this time because shared is a static variable, it only initials it once and this variable lasts forever in the AlertViewHandleLogic class. So you've successfully created a Singleton class 😻
So in reality, do we often see singletons? Oh, a lot of friends. For example, Apple has 1 piece of code in the UIKit as follows:
UIApplication.shared.keyWindow?. rootViewController
Then the variable above is singleton. In the example above, when I want to get rootViewController then I go through the shared variable of the UIApplication class to access. Since each IOS application needs a variable to save the rootViewController and only, so they create a singleton for it. The naming rule for singletons is usually shared, or getInstance() as it was in the 1980s. So you know what Singleton's effect is. Remember for ourselves we only create Singleton when:
- Manage a single variable or class that runs through the app
- Static won't be freed until the app is freed
Therefore, it is not possible to abuse Singleton or static, right? If you understand simple, swift or other programming languages have two basic variable types: dynamic and static. Dynamic initials the runtime, and releases it when the class containing it cancels. Static initials always when that class is called init, and exists throughout the application. However, many mandatory cases still have to use static whether desired or not.
In the example we do below, I want the program to after a certain period of time display a warning screen on the view controller, wherever it shows up ha. And the processing of that show is handled by the AlertViewHandleLogic class. Sounds fascinating, doesn't it? In fact, there are examples like you want after a period of time the application to lock the screen itself can also apply, and so on clouds ha.
OK to read here is tired, so let's go sing a song and then we 😷
2. Create singleton show alert management
Follow the following code:
- Line 12, 13 I have a timer variable to calculate after a period of time will show alert
- Lines 23 to 27, I create the function so that every 1 or 5s it will call the closure needShowAlertView variable. The purpose of this variable is to fire a callback for which view controller assigned will perform this action.
Go to SingletonLeakViewController and follow the following code:
- Line 15, I initially initially initially transformed the singleton variable of the AlertViewHandleLogic class
- Line 16 I assigned closure needShowAlertView and display 1 inscription need show here
- Line 20 I call the resetShowAlertTimer function for the timer to work
After build I get the following result:
So every 5s it's going to shoot out the callback so we can write the logic of showing this alert.
However, because the alertViewHandleLogic.resetShowAlertTimer() function calls cumbersomely, I will include it in the AlertViewHandleLogic init function so that I don't have to call every time I create a callback needShowAlertView.
However, there is one serious problem as follows:
- The closure needShowAlertView variable belongs to the AlertViewHandleLogic class, which is the Singleton class. Therefore, when this variable is assigned at SingletonLeakViewController, only this view shows alert. Let's assume I assign it to SecondViewController, it no longer works at SingletonLeakViewController. Oh while I want it to have to work at all the muscle viewcontrollers 😡🤬
It's hard, because singleton is only one and only, so we can't apply this closure callback technique. What is the solution?
3. Replace closure callback with observers
Pigs? Did you just show us the singleton and just just added the observers? Is that too much? 🥱😲 Oh, if you just yawn, stop making iced tea cups, smoking cigarettes, watching me sell curvy butt water for a while and then continue after.
😍's OK and now we're going to continue to study what observers are?
Observers translated in a pureLy Vietnamese sense are observers. Every timer comes to 5s, he's going to have to tell all the guys who use it to show alerts. Of course, the view controller is in display mode. How is this technique used?
You simply create a protocol in the AlertViewHandleLogic class, then you create more add functions and remove these protocols to use or delete listening protocols in the views. Protocol is responsible for notifying view controllers.
That's good to say, code 😅 follow the following code:
- Lines 11 to 14, Here I create the AlertViewHandleLogicDelegate protocol that is tasked with firing the needShowAlertView function to show alert. Some rules for writing protocols if you are not yet mastery can be viewed here ha.
- Line 18 I made an AlertViewHandleLogicDelegate-style observers variable to store the observers of the view controllers who wanted to listen to it.
Continue watching the code:
- Lines 43 to 46, I create the add observer function. I can check if it has not been added, then skip no more.
- Lines 51 to 54 I write the remove observer function. Since I don't add iterations, I only check the first one if it's the guy who needs to remove it, then remove it from the list.
In the function you edit a little as follows:
The aim is to run one lap and then give it to everyone who has added the observer. I commented on the callback by closure.
OK, so you're ready to play with the Observer. Now you go to SingletonLeakViewController and the code is as follows:
- Line 21 I add observer for SingletonLeakViewController. When add like this, it will listen to the event after 5s will show alert.
- Lines 26 through 29, because I add so the SingletonLeakViewController class must extend functions from the AlertViewHandleLogicDelegate protocol. I show print to know it works.
- In other view controllers you do the same.
And the results run as follows:
Good job. So it worked 🥰
But wait, you just told me what's going on in singletons, why are you ra ra farning now? Oh, now I'm closing in. Leak memory has already happened!
Now you add the following line of code to check singletonLeakViewController released when you click back to no:
And it doesn't jump in at all! OMG I've done something wrong 😩🥺
Then back to the problem, the addition of an observer to SingletonLeakViewController is as follows:
AlertViewHandleLogic.shared.addObserver(self)
Then this view controller has a strong reference to the AlertViewHandleLogic class. This means that the SingletonLeakViewController class is released only when the observer in AlertViewHandleLogic is released. However, AlertViewHandleLogic can not release when it has a remove function where. Yes you tell you why you did not give the remove function like this:
deinit {
NSLog("free memory SingletonLeakViewController")
AlertViewHandleLogic.shared.removeObserver(self)
}
Unfortunately, if it doesn't release it, it doesn't jump into the deinit, and if it doesn't enter, it won't run. The story has become deadlocked 😢
My solution is as follows:
- I trick when I press the back button in UIBarButtonItem, I will call the viewWillDisappear function, I will delete there:
The result is as follows:
So SingletonLeakViewController got into the deinit, which means it's 😍
However, I don't think this is actually the smartest solution, because you will have to know the trick depending on the case and release it, not always as I did above.
OK, this article is quite long, if you have any better solution of me please comment to me below this article.
Thank you for following here and hope you will learn more interesting, practical knowledge through this article. Thanks all!