Functional programming: Closure reference cycle and fix

Here, I will try to explain an example of closure reference cycle. Follow the following article to understand more about closures in swift.

Image for post
Image for post
The reference cycle looks rusty !!!

Article_1 link → Functional swift : All about closures.

Article_2 link → Lazy var in iOS swift.

Please read the above two articles to continue.

Assuming you have a good knowledge in functional programming and closures, let’s begin.

Consider a class . It is having an method which accepts a and as parameters. It also has a called which accepts nothing and returns a . It is of type .

Image for post
Image for post
closure reference cycle.

Here, when we call the init method , a new object is created . We assign this object to an optional type .

In the next line, when we set the value of to , the method will get called. You can see the console printing the text given inside the method.

Now, try to acces the closure after creating the object. Then try to set the object to .

var humanObj:Human? = Human(firstName: “John”, lastName: “Doe”)let fullName = humanObj?.fullNamehumanObj = nil

The method will not be called as the closure holds a strong reference to .

deinit method will get called when an object is deallocated.

The fix

We can break this strong reference cycle using in the capture list with either a or an reference. If you don’t know what a capture list is, go through the article mentioned at the top.

weak

A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behaviour prevents the reference from becoming part of a strong reference cycle.

Since a weak reference may be , the variable captured becomes optional. Therefore, we should use a to safely unwrap it:

lazy var fullName:() -> String = { [weak self] inguard let weakSelf = self else { return “”}return “\(weakSelf.firstName) \(weakSelf.lastName)”}

Unowned

Like a weak reference, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime

lazy var fullName:() -> String = { [unowned self] inreturn “\(self.firstName) \(self.lastName)”}

This means that we should use just when we are sure that the reference will never be inside the closure, otherwise the app would crash. So, guard check is not required here.

We can use and with any variable in the capture list and we can also combine with the aliases:

lazy var fullName:() -> String = { [unowned unownedSelf = self] inreturn “\(unownedSelf.firstName) \(unownedSelf.lastName)”}

How to capture self with closures having arguments?

Well, you should capture the before the internal closure parameter or before the parenthesis of internal parameters. Check the code below. It explains how to capture self in a single parameter case. If you have multiple parameters, you may also use parenthesis.

Image for post
Image for post
capturing self along with closure parameters

IMPORTANT: For non-escaping closures, we don’t have to worry about capturing the self using weak or unowned keywords. It matters only for escaping closures.

Exceptional cases:

Although it is good practice to capture weakly in closures, it is not always necessary. Closures that are not retained by the can capture it strongly without causing a retain cycle. A few common examples of this are:

Working with , closures in GCD

DispatchQueue.main.async {
self.doSomething() // Not a retain cycle
}
UIView.animate(withDuration: 1) {
self.doSomething() // Not a retain cycle
}

Another interesting place where would not need to be captured strongly is in variables, that are not closures, since they will be run once (or never) and then released afterwards:

lazy var fullName = {
return self.firstName + " " + self.lastName
}() // not retained. no need to use self with weak or unowned

However, if a variable is a closure, it would need to capture self . The closure in the Human class is a good example for this.

Enjoy!!

If you enjoyed reading this post, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!

You can follow me on Medium for fresh articles. Connect with me on LinkedIn.

If you have any comment, question, or recommendation, feel free to post them in the comment section below!

Written by

iOS and tvOS developer, dreamer, photographer 🤨

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store