iOS Memory management. Closures - ios

I have a question about memory management in iOS.
As I know we have ARC that looks at a number of strong references to the object and once it's become 0 object will be deallocated.
Here is a code sample that makes me confused
final class SecondVC: UIViewController {
let titleLabel: UILabel = UILabel()
let network = Network()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .red
self.view.addSubview(titleLabel)
network.makeCall {
self.titleLabel.text = "Title"
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.popViewController(animated: true)
}
deinit {
print("SecondVC deinit called")
}
}
final class Network {
func makeCall(completion: #escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
}
}
deinit {
print("Network deinit called")
}
}
As I understand VC holding network with a strong reference.
At the same time network capture VC with a strong reference.
The completion callback was never called. So the number of references shouldn't go to 0.
But deinit called for both objects.
The questin is
Is there a memory leak? And why deinit is called if in theory we have object that should not be deallocated.
UPD
So, the answer is.
No one captures completion. Completion is released after makeCall and self captured by it is also released.

As you are using #escaping in your closure there is nothing hanging on to the reference so the count can be reset
here's a good article on #escaping
https://www.donnywals.com/what-is-escaping-in-swift/
** Edit,
Sorry this was poorly worded - "in your closure there is nothing hanging on to the reference" was the key bit from this as the closure is never called - the escaping part was confusing things as its really unrelated to the OP's question, sorry for the confusion

Related

iOS/Swift - What is the difference between Closure/Completion blocks and Delegates/functions?

I don't clear about these two, Nowadays the world is shifting to the closure types. But I'm not clearly understanding this. Can someone explain me with a real-time example?
So a real life example of both would be something like this:
protocol TestDelegateClassDelegate: class {
func iAmDone()
}
class TestDelegateClass {
weak var delegate: TestDelegateClassDelegate?
func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.delegate?.iAmDone()
}
}
}
class TestClosureClass {
var completion: (() -> Void)?
func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.completion?()
}
}
}
class ViewController: UIViewController, TestDelegateClassDelegate {
func iAmDone() {
print("TestDelegateClassDelegate is done")
}
override func viewDidLoad() {
super.viewDidLoad()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
let testingClosure = TestClosureClass()
testingClosure.completion = {
print("TestClosureClass is done")
}
testingClosure.doStuff()
}
}
Here we have 2 classes TestDelegateClass and TestClosureClass. Each of them have a method doStuff which waits for 3 seconds and then reports back to whoever is listening where one uses delegate procedure and the other one uses closure procedure.
Although they do nothing but wait you can easily imagine that they for instance upload an image to server and notify when they are done. So for instance you might want to have an activity indicator running while uploading is in progress and stop it when done. It would look like so:
class ViewController: UIViewController, TestDelegateClassDelegate {
#IBOutlet private var activityIndicator: UIActivityIndicatorView?
func iAmDone() {
print("TestDelegateClassDelegate is done")
activityIndicator?.stopAnimating()
}
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator?.startAnimating()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
activityIndicator?.startAnimating()
let testingClosure = TestClosureClass()
testingClosure.completion = {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
testingClosure.doStuff()
}
}
Naturally you would only use one of the two procedures.
You can see there is a huge difference in code. To do a delegate procedure you need to create a protocol, in this case TestDelegateClassDelegate. A protocol is what defines the interface of a listener. And since an iAmDone method is defined it must be defined in ViewController as well as long as it is defined as TestDelegateClassDelegate. Otherwise it will not compile. So anything declared as TestDelegateClassDelegate will have that method and any class can call it. In our case we have weak var delegate: TestDelegateClassDelegate?. That is why we can call delegate?.iAmDone() without caring what delegate actually is. For instance we can create another class:
class SomeClass: TestDelegateClassDelegate {
func iAmDone() {
print("Something cool happened")
}
init() {
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
}
}
So a good example for instance is an UITableView that uses a delegate and dataSource (both are delegates, just properties are named differently). And table view will call the methods of whatever class you set to those properties without needing to know what that class is as long as it corresponds to the given protocols.
Same could be achieved with closures. A table view could have been defined using properties giving closures like:
tableView.onNumberOfRows { section in
return 4
}
But that would most likely lead into one big mess of a code. Also closures would in this case be giving many programmers headaches due to potential memory leaks. It is not that closures are less safe or anything, they just do a lot of code you can't see which may produce retain cycles. In this specific case a most likely leak would be:
tableView.onNumberOfRows { section in
return self.dataModel.count
}
and a fix to it is simply doing
tableView.onNumberOfRows { [weak self] section in
return self?.dataModel.count ?? 0
}
which now looks overcomplicated.
I will not go into depths of closures but in the end when you have repeated call to callbacks (like in case of table view) you will need a weak link either at delegate or in closure. But when the closure is called only once (like uploading an image) there is no need for a weak link in closures (in most but not all cases).
In retrospective use closures as much as possible but avoid or use caution as soon as a closure is used as a property (which is ironically the example I gave). But you would rather do just this:
func doSomethingWithClosure(_ completion: #escaping (() -> Void)) {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
completion()
}
}
And use it as
doSomethingWithClosure {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
This has now removed all potential risks. I hope this clears a thing or two for you.
In Swift/obj-c the term delegate is used to refer to a protocol that responds to specific selectors.
Thing about it just like calling a method on an object.
E.g.
protocol CalculatorDelegate : class { // : class so it can be made 'weak'
func onCalculation(result: Int) -> Void
}
Now if we have a Calculator class, to use the delegate we'd do something like
class Calculator() {
weak var delegate: CalculatorDelegate?
func calculate(_ a: Int, _ b: Int) -> Int {
let result = a + b
self.delegate?.onCalculation(result: result)
return result
}
}
Then in some other class (e.g. in iOS - a View Controller) we might do:
class MyClass : CalculatorDelegate {
func onCalculation(result: Int) {
print("Delegate method on calculation called with result \(result)")
}
func someButtonPress() {
let calculator = Calculator()
calculator.delegate = self
calculator.calculate(42, 66)
}
}
So you can see how the setup is quite elaborate.
Now closures are simply blocks of code that can be called in other places, so you could change all of the code like so:
class Calculator2() {
weak var delegate: CalculatorDelegate?
func calculate(_ a: Int, _ b: Int, onCalculation: (#escaping (Int) -> Void) -> Int)?) {
let result = a + b
onCalculation?(result)
return result
}
}
class MyClass {
func someButtonPress() {
let calculator = Calculator2()
calculator.calculate(42, 66, onCalculation: { (result: Int) in
print("Closure invoked with \(result)")
})
}
}
However, with closures you need to be aware that it is a lot easier to shoot yourself in the foot by capturing variables (e.g. self) strongly, which will lead to memory leaks even under ARC regime.
Closures are first-class objects so that they can be nested and passed around
Simply,
In swift, functions are primitive data types like int, double or character that is why you can pass a function in the function parameter. In swift mechanism simplify in closures syntax like lambda expression in other languages.
E.g. If you want to call rest API through URSSession or Alamofire and return response data then you should use completionHandler(it's closure).
Void closure : - {(paramter:DataType)->Void}
Return closure : - {(paramter:DataType)->DataType}
e.g. (int, int) -> (int)
https://docs.swift.org/swift-book/LanguageGuide/Closures.html

Are there problems with strong retain issues with code such as this:

In the following code, is there a problem with the self in self.tableView.reloadData() being a strong reference, and should it be changed to be weak, or is it ok as it is?
class SomeViewController : UIViewController {
fileprivate var notificationToken: NotificationToken? = nil
...
override func viewDidLoad()
{
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(onNotification), name: NSNotification.Name(SomeNotification), object: nil)
realmNotificationToken = blockedList.observe({ (changes: RealmCollectionChange) in
switch changes
{
case .initial:
self.tableView.reloadData() // Case 1
break
...
#objc func onNotification()
{
DispatchQueue.main.async{
self.tableView.reloadData() // Case 2
}
}
In both of these examples are there any problems with retain cycles due to the fact self is a strong reference, and it should change to weak?
In both instances, what is the life time of the two blocks within which self.tableView.reloadData() is being used? If the lifetime is ephemeral then there's no problems with using strong, are these blocks however long lived?
Case 2 is a non escaping closure so there is no issue.
Case 1 is #escaping so you need to use a weak or unowned reference. #escaping means you are passing the closure to something that may outlive the object that created the closure (ie you ViewController). If you strongly capture self in the #escaping then your ViewController now lives for as long as the closure lives, and the closure lives until you cancel your subscription. If you only cancel the subscription when the ViewController deintializes then you now have a cycle. The closure can never be released because the subscription never dies and the ViewController can never die because the subscription never dies.
EDIT:
I should add you actually don't need self in either case; you can simply capture the tableview (if its implicitly unwrapped it will be desugared into a plain optional, which is fine):
realmNotificationToken = blockedList.observe({ [tableView] (changes: RealmCollectionChange) in
switch changes {
case .initial:
tableView?.reloadData()

Why is this a retain cycle?

I have basic understanding of ARC but in the following example I suddenly get really confused.
FeedViewController has a strong reference of NetworkHelper, then the NetworkHelper has a function which takes a closure and call it later.
So here's the confusion:
the closure is passed from FeedViewController to NetworkHelper, And this block is not being retained inside NetworkHelper, so why does NetworkHelper has a strong reference of NetworkHelper? this is stated in an article but I just could't figure out why. It makes sense to me only if NetworkHelper keep a strong reference to the block.
class NetworkHelper {
func getFeed(completion: #escaping ([FeedItem]) -> Void) {
Alamofire.request(…).responseJSON { (response) in
if let value = response.result.value {
if let json = JSON(value)[Constants.items].array {
completion(json.flatMap(FeedItem.init))
}
}
}
}
}
class FeedViewController {
var tableView: UITableViewController
var feedItems: [FeedItem]
var networkHelper: NetworkHelper
override func viewDidLoad() {
...
networkHelper.getFeed() { items in
self.feedItems = items
self.tableView.reloadData()
}
}
}
Technically, there is no cycle.
First of all, NetworkHelper never owns anything, it just passes a closure to Alamofire.
Alamofire holds to that closure, which retains a FeedViewController instance (as self). However, Alamofire is not owned by FeedViewController, therefore there is no cycle.
It's true that while the request is running, FeedViewController cannot be deallocated because the completion callback prevents that, but that could be an expected behavior and there is definitely no ownership cycle.

set delegate to self but the result is nil

I had set my delegate to self sometimes, just sometimes, the delegate won't set. It is nil. It seems like some memory management issue. I want to know is there any solution to solve this without any memory leak? I will copy my code and my debugging steps in here.
func openConversationForPost(_ post: PostViewStructure, viewController: UIViewController) {
let dest = ChatViewController(service: service, conversationID: post.token!)
dest.delegate = self
viewController.navigationController?.pushViewController(dest, animated: true)
}
ps1. I know I can use strong but then there will be high risk of crashing.
ps2. The weird thing is when I set the break right on the line where the delegate is being set there is no problem; but, if I let the flow of the programming running normally the delegate is nil.
Edit
The init func of ChatViewController
init(service: ServicesProtocol, conversationID: String) {
self.conversationID = conversationID
super.init(service: service)
defer { conversation = DataProvider().object(ChatConversation.self, key: conversationID) }
}

About strong reference cycles for closures in Swift

I have defined a class called Person. This is my code:
class Person {
var closure: (() -> ())?
var name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
then I use Person in class called ViewController:
class ViewController: UIViewController {
var person = Person(name: "john")
let aStr = "john is a cute boy"
override func viewDidLoad() {
super.viewDidLoad()
person.closure = {
print("\(self.aStr)")
}
person.closure!()
}
}
In my opinion, the picture of memory about my code like this :
So, from above picture, in my opinion, it will cause strong reference cycle between the three instances, but I can not get any leak from Instruments, so I have some confusion.
Does this code cause strong reference cycle?
If not, when will ARC deallocate the instance of Person? the method named deinit in Person class is never called.
Yes, this's a typical retain cycle.
To solve this problem use [weak self] in your closure
person.closure = { [weak self] in
guard let strongSelf = self else { return }
print("\(strongSelf.aStr)")
}
To really create a leak.
I create a demo App. Root is a navController.
The navController has a root controller. Let's call it buttonController.
When you click button in the buttonController, it create your ViewController and push to navController.
When you click back button in navigation bar, the navController pop your ViewController instance.
Profile it, then you will see the leak and the retain cycle in Instruments.
Xcode default template of iOS App use a single page, which always retain your ViewController instance. If the ViewController instance is still used by the system, it's actually not a leak yet.
So push & pop show that leak for you.

Resources