”;
Automatic Reference Counting in Swift
Automatic Reference Counting(ARC) is a memory management mechanism used by Swift, it automatically tracks and manages the allocation and deallocation of objects’s memory. Or we can say that it is used to initialize and deinitialize the system resources thereby releasing memory spaces used by the class instances when the instances are no longer needed. It keeps track of information about the relationships between the instances to manage the memory resources effectively. ARC is generally applicable only to instances of classes because they are reference types.
Working of ARC
-
ARC allocates a chunk of memory to store the information whenever a new class instance is created by init().
-
Information about the instance type and its values are stored in the memory.
-
When the class instance is no longer needed it automatically frees the memory space by deinit() for further class instance storage and retrieval.
-
ARC keeps in track of currently referring class instances properties, constants and variables so that deinit() is applied only to those unused instances.
-
ARC maintains a ”strong reference” to those class instance properties, constants and variables to restrict deallocation when the class instance is currently in use.
Example
Swift program to demonstrate ARC.
class StudDetails { // Properties var stname: String var mark: Int // Initializer to initialize instances of the class init(stname: String, mark: Int) { self.stname = stname self.mark = mark } // Deinitializer to deinitialize the instances of // the class when they are no longer required deinit { print("Deinitialized (self.stname)") print("Deinitialized (self.mark)") } } // Creating class instance var obj1 = StudDetails( stname:"Swift", mark:98) // Creating another class instance var obj2: StudDetails? = StudDetails(stname: "iOS", mark: 95) // Setting anotherObj to nil to deallocate the memory obj2 = nil
Output
It will produce the following output −
Deinitialized iOS Deinitialized 95
Strong Reference Cycles Between Class Instances in Swift
ARC is used to automatically manage memory by keeping track of object references. However, there is a challenge faced by the developers which is the creation of a strong reference cycle, where two or more objects have strong references to each other which prevents their reference counts from reaching zero and due to this a memory leakage happens.
Example
Swift program to demonstrate strong reference cycles between class instances in Swift.
class studmarks { let name: String var stud: student? // Initializer init (name: String) { print("Initializing: (name)") self.name = name } // Deinitializer deinit { print("Deallocating: (self.name)") } } class student { let name: String var strname: studmarks? // Initializer init (name: String) { print("Initializing: (name)") self.name = name } // Deinitializer deinit { print("Deallocating: (self.name)") } } // Declare optional variables for instances var shiba: studmarks? var mari: student? shiba = studmarks(name: "Swift 4") mari = student(name: "ARC") // Create a strong reference cycle by assigning references to each other shiba!.stud = mari mari!.strname = shiba
Output
It will produce the following output −
Initializing: Swift 4 Initializing: ARC
To resolve strong reference cycles Swift provides Weak and Unowned References. These references are used to enable one instance to refer to other instances in a reference cycle. Then the instances may refer to every instance instead of caring about a strong reference cycle.
Weak References
It is an optional reference to an object that does not keep a strong hold on the object. It will return nil when the object it refers to is deallocated. It is generally used where the referenced object’s lifecycle is not guaranteed to outlive the referencing object. It is commonly used for relationships where the referenced object can deallocate independently. We can declare weak references using the weak Keyword.
Syntax
Following is the syntax for weak reference −
class Class1 { var name: Name? } class Name { weak var teacher: Class1? }
Example
Swift program to demonstrate weak references.
class module { let name: String init(name: String) { self.name = name } var sub: submodule? deinit { print("(name) Is The Main Module") } } class submodule { let number: Int init(number: Int) { self.number = number } weak var topic: module? deinit { print("Sub Module with its topic number is (number)") } } var toc: module? var list: submodule? toc = module(name: "ARC") list = submodule(number: 4) toc!.sub = list list!.topic = toc toc = nil list = nil
Output
It will produce the following output −
ARC Is The Main Module Sub Module with its topic number is 4
Unowned References
It is a non-optional reference to an object that does not keep a strong hold on the object as compared to a weak reference. It assumed that the reference object will never become nil, while the reference object is still alive. It is generally used where you know that the referenced object’s life is guaranteed to be at least as long as the referencing object’s lifetime. It is commonly used for relationships where the referenced object has the same or longer lifetime as compared to the referencing object. We can declare unowned references using the unowned Keyword.
Syntax
Following is the syntax for unowned reference −
class Class1 { var name: Name? } class Name { unowned var teacher: Class1 }
Example
Swift program to demonstrate Unowned references.
class student { let name: String var section: marks? init(name: String) { self.name = name } deinit { print("(name)") } } class marks { let marks: Int unowned let stname: student init(marks: Int, stname: student) { self.marks = marks self.stname = stname } deinit { print("Marks Obtained by the student is (marks)") } } var module: student? module = student(name: "ARC") module!.section = marks(marks: 98, stname: module!) module = nil
Output
It will produce the following output −
ARC Marks Obtained by the student is 98
Strong Reference Cycles for Closures
When we assign a closure to the class instance property and to the body of the closure to capture particular instance strong reference cycle can occur. Strong reference to the closure is defined by ”self.someProperty” or ”self.someMethod()”. Strong reference cycles are used as reference types for the closures.
Example
Swift program to demonstrate Strong Reference Cycles for Closures.
class HTMLElement { let samplename: String let text: String? lazy var asHTML: () -> String = { if let text = self.text { return "<(self.samplename)>(text)</(self.samplename)>" } else { return "<(self.samplename) />" } } init(samplename: String, text: String? = nil) { self.samplename = samplename self.text = text } deinit { print("(samplename) is being deinitialized") } } var paragraph: HTMLElement? = HTMLElement(samplename: "p", text: "Welcome to Closure SRC") print(paragraph!.asHTML())
Output
It will produce the following output −
<p>Welcome to Closure SRC</p>
Resolving Strong Reference Cycles for Closures
We can resolve the strong reference cycles for closures using Weak and Unowned References. When the closure and the instance refer to each other the user may define the capture in a closure as an unowned reference. Then it would not allow the user to deallocate the instance at the same time. When the instance sometimes returns a ”nil” value define that closure with the weak instance.
Example
class HTMLElement { let module: String let text: String? lazy var asHTML: () -> String = { [unowned self] in if let text = self.text { return "<(self.module)>(text)</(self.module)>" } else { return "<(self.module) />" } } init(module: String, text: String? = nil) { self.module = module self.text = text } deinit { print("(module) the deinit()") } } var paragraph: HTMLElement? = HTMLElement(module: "Inside", text: "ARC Weak References") print(paragraph!.asHTML()) paragraph = nil
Output
It will produce the following output −
<Inside>ARC Weak References</Inside> Inside the deinit()
”;