Using Strong
If your singleton’s block code strongs the viewcontroller, it will keep the ViewController around.
1) Your singletons starts processing data
2) You exit (cancel/pop) your ViewController. At this point ViewController will not dealloc because the block of your Singleton has stronged ViewController
3) Your function finishes processing
4) Then it executes its callback (block code). It goes through the print statements, then uses the strong self, and calls ViewControler’s random(). When all of that is done. The code block is finished. The local stack is popped, including the self reference. Thus, this nils the strong to the ViewController.
5) In Swift, it still remembers that the user wanted to cancel the ViewController. Thus, when it notices that is it not stronged by the block’s self anymore, it goes ahead and deallocates. Thus, avoiding floating around uncollected in memory.
In objective-C, it does not remember that the user wants to dealloc the ViewController. Since it is stronged by the block’s self, it won’t call dealloc. When the block is done and pops its local stack the and strong self reference, the ViewController is still there. It does not remember that the user wants to exist and thus, does not re-evaluate its strong reference count. Therefore, your ViewController becomes an uncollected object in memory. Thus, the way it works in Swift is an improvement over Objective C.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// due to your block strong-ing this ViewController, if you try popping this ViewController, // your deinit WILL NOT be called. // Rather, swift will remember your popping of the ViewController. After this block is done, // it will then process your popping of the ViewController by calling deinit. MySingleton.shared.processSomeBigDataThatTakesLongTime { (error) in if(error==nil) { print("Do something here, update UI, check some stuff, etc...") print("---------------------------------------") self.random() } } |
After our singleton finishes processing all that data, it runs through the block code, sends whatever message it needs to the strong self. At the end of the code block, the local stack pops, thus removing the strong to the ViewController. The ViewController will only dealloc/deinit itself when it sees that there is no strong reference to it. That’s why in the log, you’ll see all the processing and block code print logs, and then execution hits the ViewController’s dealloc/deinit.
You will see that the block code successfully uses the strong self to send a message to ViewController’s function and displays log. This is because ViewController is still around. If we are to use weak, ViewController will not be around, and you won’t be able to log, as you will see from the weak example below.
Using weak
1 2 3 4 5 6 7 8 |
weak var weakSelf = self MySingleton.shared.processSomeBigDataThatTakesLongTime { (error) in if(error==nil) { print("Do something here, update UI, check some stuff, etc...") print("---------------------------------------") weakSelf?.random() } } |
MySingleton’s block has a weak pointing to the ViewController. When that ViewController get popped, it will see that it DOES NOT have any strong references to it, thus calling its de-init function:
NOTICE HERE that even though the singleton function is still processing data, ViewController went ahead and de-inited in the middle of the process.
This is because ViewController has no other strong references pointing to it.
Now, what happens when Data finishes processing and the callback access the deallocated ViewController’s function?
When MySingleton.shared.processSomeBigDataThatTakesLongTime finishes, it will process its callback and execute the block below:
1 2 3 4 5 |
if(error==nil) { print("Do something here, update UI, check some stuff, etc...") print("---------------------------------------") weakSelf?.random() } |
Notice it calls ViewController’s random function. However, ViewController has already been deallocated and its memory address has junk. Thus, the weakSelf reference will nil itself (A weak reference will automatically get nil when its referenced object is deallocated). Thus, nothing happens when we try to dereference it and call random().
As you can see, calling random() does nothing because ViewController object is not there to process it.