Resolving Leaky Closures in Swift
left arrow

Resolving Leaky Closures in Swift

24 October, 2019

BACK TO BLOG
right arrow

Closures are self-contained blocks of functionality that can be passed around and used in your code. They are similar to blocks in C and Objective-C and lambda functions in other programming languages. Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables.

Closures is a powerful feature in Swift, but it does demand caution in some cases.

Classes and Closures are both reference types. Because a closure can capture values from its surrounding scope, a closure can create a reference cycle.

For example:

class User {

        let firstName: String

        let lastName: String

        lazy var fullName: () -> String = {

        return "\(self.firstName) (\(self.lastName))"

        }


init(firstName: String, lastName: String) {

        self.firstName = firstName

        self.lastName = lastName

        }


deinit {

        print("Deallocated User")

        }
}

var newUser: User? = User(firstName: "John", lastName: "Doe")



user?.fullName()

user = nil

As we know, all references declared in Swift are by default strong references. The newUser instance of the User class, holds a strong reference to the Closure stored in the fullName property. And, the Closure stored in the fullName property also holds a strong reference to the newUser instance i.e. self. This results in what we call as a strong reference cycle. Being a cyclic reference, the deinit of the class is never involved, and the ARC will never remove the reference from memory thus leading to a memory leak.

This is a typical situation that demands caution whilst using Closures. To resolve this kind of a problem we can use a Capture List…

Defining a Capture List

The references a Closure holds to reference types are strong by default. We can change this behaviour by defining a capture list. The capture list determines how values used inside the closure should be captured.

Weak capturing

A weak reference type keeps a weak reference to the instance it references. This means that the reference to the instance will not be accounted for by the ARC. A weak instance is deallocated if there exists no other strong reference to the instance.

class User {

        let firstName: String

        let lastName: String

        lazy var fullName: () -> String = { [weak self] in

        return "\(self.firstName) (\(self.lastName))"

        }

}

In the above code, the “weak self” defines the reference to the self within the closure, as a weak reference, and hence the cyclic reference is avoided.

Unowned capturing

Unowned references are similar to weak references in that they don’t keep a strong reference to the instance they are referencing. The difference is unowned reference is always expected to have a value.

class User {

        let firstName: String

        let lastName: String

        lazy var fullName: () -> String = { [unowned self] in

        return "\(self.firstName) (\(self.lastName))"

        }

}

The above 2 examples show how Capture list can be used to avoid reference cycles and hence memory leaks in closures.

Synsoft Global has a team of developers based in India who work remotely on projects for clients in countries like the USA, UK, Germany, UAE. We have the experience and the talent that has helped many American businesses streamline their software development process and improve their overall efficiency by swiftly hiring resources from us in India.

Looking to Hire Mobile development Experts?

AUTHOR

Anjali Surana

Have a project in mind?

Let's Discuss!

Build stunning & premium web apps with our top-rated Development Team & Accomplish your Business Goals Lightning Fast.

book your slot

Our Services

Featured Blogs

blog image

Have a project in mind?

Let's Discuss!

Build stunning & premium web apps with our top-rated Development Team & Accomplish your Business Goals Lightning Fast.

HIRE FROM US

Mailing Address

403/404, Airen Heights, Scheme 54, A. B. Road,
Indore 452010 (MP), INDIA

539 W. Commerce St #2531
Dallas, TX 75208, USA

Phone Number

Instagram iconTwitter iconLinkedIn iconFacebook iconBehance icon
ISO certificate

© COPYRIGHT SYNSOFT GLOBAL 2024

PRIVACY POLICY