This is the 24th day of my participation in Gwen Challenge

Automatic reference counting

Swift uses an automatic reference counting (ARC) mechanism to manage your application’s memory. In general, Swift memory management will always work and you don’t have to worry about memory management yourself. ARC automatically frees up memory for instances of classes when they are no longer in use

Reference counting applies only to instances of a class. Struct and enumeration types are value types and do not fit


Automatic reference counting (number of times an object is referenced)

  • Each time an instance object of a class is created, ARC allocates a block of memory to store instance information (instance type information and instance storage properties)
  • ARC frees the memory occupied by the instance when it is no longer in use, which ensures that instances that are no longer in use do not occupy the memory space all the time
  • When ARC releases an instance in use, its properties and methods can no longer be accessed or called. In fact, if you try to access this instance, your application will probably crash
  • To ensure that instances in use are not destroyed, ARC tracks and calculates how many properties, constants, and variables each instance is being referenced by. ARC does not destroy an instance even if its number of references is 1
class Student{
    let name:String
    init(name:String) {
        self.name = name
        print("init")
    }
    deinit {
        print("deinit")}}var stu0:Student?        //nil
var stu1:Student?        //nil
var stu2:Student?       //nil

stu0 = Student.init(name: "lilei")  // Print log: init
stu1 = stu0
stu2 = stu0
stu0 = nil
stu1 = nil
stu2 = nil    // Print log: deinit
Copy the code

Cyclic strong references between class instances

  • Both class instances hold a strongly referenced property to each other, which is known as circular strong references
  • The relationship between classes replaces strong references with weak references to solve the problem of cyclic strong references

class ClassA{
    
    let aStr:String
    var b:ClassB?

    init(str:String) {
        self.aStr = str
    }
    deinit {
        print("ClassA release")}}class ClassB{
    
    let bStr:String
    var a:ClassA?

    init(str:String) {
        self.bStr = str
    }
    deinit {
        print("ClassB release")}}var objA:ClassA?
var objB:ClassB?

objA = ClassA(str: "A")
objB = ClassB(str: "B") objA! .b = objB objB! .a = objA objA = nil objB = nilCopy the code

Resolve circular references between classes

  • Weak references: Referenced instances are not preserved
    • When declaring a property or variable, prefixweakThe keyword indicates that this is a weak reference
    • ARC automatically assigns a nil value to the referenced instance after it is destroyed

class ClassA{
    
    let aStr:String
    var b:ClassB?

    init(str:String) {
        self.aStr = str
    }
    deinit {
        print("ClassA release")    // Print normally}}class ClassB{
    
    let bStr:String
    weak var a:ClassA?

    init(str:String) {
        self.bStr = str
    }
    deinit {
        print("ClassB release")   // Print normally}}var objA:ClassA?
var objB:ClassB?

objA = ClassA(str: "A")
objB = ClassB(str: "B") objA! .b = objB objB! .a = objA objA = nil objB = nilCopy the code
  • Unoccupied Reference: An instance property modified by an unoccupied reference has the same life cycle as the instance referencing it
    • When declaring a property or variable, prefix it with a keywordunownedIndicates that this is an ownerless reference
    • With an undirected reference, you must ensure that the reference always points to an undestroyed instance
    • A runtime error is triggered if you attempt to access an unclaimed reference to an instance after it has been destroyed

class ClassA{
    
    let aStr:String
    var b:ClassB?

    init(str:String) {
        self.aStr = str
    }
    deinit {
        print("ClassA release")   // Print normally}}class ClassB{
    
    let bStr:String
    unowned var a:ClassA?

    init(str:String) {
        self.bStr = str
    }
    deinit {
        print("ClassB release")   // Print normally}}var objA:ClassA?
objA = ClassA(str: "A") objA! .b = ClassB(str:"B")
objA = nil  // When objA is freed, ClassB is freed
Copy the code

Circular strong references caused by closures

When a closure is assigned to a property of a class instance and the class instance is used in the closure. The closure might access an instance property, such as self.someProperty, or call an instance method, such as self.somemethod (). Both cases cause the closure to “capture” self, resulting in circular strong references

class ClassA{
 
    let strA: String
    let showValue:Bool

    // Defines a lazy attribute that refers to strA closures. It is of type Void -> String
    // By default, closures are assigned to closures. This closure returns a string

    lazy var closures: () -> String = {
        
        if self.showValue {
            return self.strA
        } else {
            return "Empty."}}init(str:String, show:Bool) {
        self.strA = str
        self.showValue = show
    }
    deinit {
        print("A release." ")}}var objA:ClassA?
objA = ClassA.init(str: "AA".show: true)
var log:String= objA! .closures() print(log) objA = nil// Print: A release
Copy the code

Resolve circular strong references caused by closures

When you define a closure, you define a catch list as part of the closure. The catch list defines the rules within the closure for capturing one or more reference types. Declare each captured reference as weak or undirected, just as you would resolve circular strong references between two class instances

  • Defining a capture list

Each item in the capture list consists of a pair of elements, one of which is the weak or unowned keyword, and the other is a reference to the class instance (such as self) or an initialized variable (such as delegate = self.delegate!). , these items are separated by commas in square brackets

  • If the closure has argument lists and return types, place the capture list in front of them
 lazy var someClosure: (Int, String) - >String= { [unowned self, weak delegate = self.delegate!]  (index: Int,stringToProcess: String) - >String in
      // Here is the body of the closure
  }
Copy the code
  • If the closure does not specify argument lists or return types, that is, they are inferred from context, then you can place the capture list and the keyword IN at the beginning of the closure
    lazy var someClosure: Void -> String = {
        [unowned self, weak delegate = self.delegate!] in
    // Here is the body of the closure
  }
Copy the code
  • Weak references: A capture within a closure is defined as a weak reference when the captured reference might become nil
  • Unoccuted Reference: A capture within a closure is defined as an unoccuted reference when the instances of the closure and capture always reference each other and are always destroyed at the same time
  • If the captured reference never becomes nil, use an ownerless reference, not a weak reference

class ClassA{
 
    let strA: String
    let showValue:Bool
    // Defines a lazy attribute that refers to strA closures. It is of type Void -> String
    // By default, closures are assigned to closures. This closure returns a string
    lazy var closures: () -> String = {
          
        // The catch list is [unowned self], which means "catch self as an unreferred reference instead of a strong reference"
        [unowned self]   in
       
        if self.showValue {
            return self.strA
        } else {
            return "Empty."}}init(str:String, show:Bool) {
        self.strA = str
        self.showValue = show
    }
    deinit {
        print("A release." ")}}var objA:ClassA?
objA = ClassA.init(str: "AA".show: true)
var log:String= objA! .closures() print(log) objA = nil print: AA A releaseCopy the code