JavaScript Required

We're sorry, but we doesn't work properly without JavaScript enabled.

How to use the capture list in Swift and avoid retain cycles in closure

Swift is a modern, high-level programming language which automatically manages much of the memory of the iOS applications, which means it allocates and de-allocates memory on its own. It uses the concept called Automatic Reference Counting (or simply ARC) which allows it to manage the memory. In most cases, Swift memory management works automatically.

Closures

Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and lambdas in other programming languages.

A closure can capture and store references to any constants and variables from the context in which they defined. It is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.

Since closures in Swift are a reference type, a retain cycle can create, especially when self-captured within it.

The below example shows how a strong retain cycle is created using a closure.

class Test { var myClosure = { self.callFunction() } }

In this example Test class has a strong reference to myClosure and myClosure closure captures self strongly by calling callFunction(). To avoid reference cycle, we need to be captured variables as weak or unowned.

Weak vs Unowned

Let’s discuss the strong reference first. Capturing variable means that the referred object will not be non-allocated from memory because the count of the reference or the count of an object can be increased by 1. As long as an object whose reference count or retain count is greater than 0, that object won’t get de-allocated by ARC.

In the above example, callFunction() referred strongly. Hence it’s reference count is increased by 1 and won’t get de-allocated causing a memory leak.

A weak reference is just a pointer that points to an object. It doesn’t increase the retain count or reference count. As the retain count is not increased using weak, the object can be de-allocated by ARC.

In the below example, the self-captured as weak.

class Test { var myClosure = { [weak self] in self?.callFunction() } }

Just after the opening of curly braces at the declaration of myClosure, inside the square bracket, weak self ([weak self]) is written, which means self is captured as weak, followed by in keyword. This square bracket is called a capture list.

You must be wondering about the ? (question mark) after self. As the reference count might be zero when nothing holds a strong reference to this object, it might be de-allocated. Hence it can be nil and treated as on Optional.

Unowned behaves similarly to weak, but both are not the same. Just like weak, unowned does not increase the retain cycle, but the object can’t be nil.Unowned should only be used where one is sure the object won’t be nil. If accessing an object captured as unowned and the object is nil, a run time error will generate.

In the below example self is captured as unowned instead of weak

class Test { var myClosure = { [weak self] in self?.callFunction() } }

As the self-captured as unowned, the self is not an option and hence? (Question mark) can’t be used.

class Test { var myClosure = { [unowned self, weak sampleDelegate = self. sampleDelegate] in self.callFunction() sampleDelegate?.myClosureCalled() } }

In this example, the self-captured as weak and sampleDelegate captured as unowned. As the self is unowned, ? Is not required as it assumes that self will be in memory when the closure executed. However upon calling myClosureCalled() on sampleDelegate, sampleDelegate? (With a question mark) is used as sampleDelegate is captured as weak and by the definition of weak, treated as an optional as it can be nil.

Conclusion

Capturing an object or value which is getting used inside a closure is a pretty neat feature. But it might introduce strong retain cycles or reference cycles if not used properly. When working with closures, be mindful about capture list. If any value or object is getting used inside a closure, capture it using unowned or weak. Also, use unowned only when you are a hundred percent sure that the object or value will be in memory and won’t be nil.

This blog is for reference purposes, by the experienced iPhone app programmers of Nex Mobility, our team is always ready to build innovative and also assist you 24/7 support.