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, prefix
weak
The keyword indicates that this is a weak reference - ARC automatically assigns a nil value to the referenced instance after it is destroyed
- When declaring a property or variable, prefix
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 keyword
unowned
Indicates 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
- When declaring a property or variable, prefix it with a keyword
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