Swift uses an automatic reference counting (ARC) mechanism to track and manage your App’s memory. In most cases, this means that Swift’s memory management mechanism will always work and you don’t need to worry about memory management yourself. ARC automatically frees the memory occupied by class instances when they are no longer needed. Using ARC in Swift is very similar to using ARC in Objective-C.
Class instances have reference counts. Structs and enumerations are value types that are not reference types and do not have reference counts.
How ARC works
Each time you create an instance of a class, ARC allocates a large chunk of memory to store information about that instance. This memory holds information about the type of the instance, as well as information about all the stored attribute values of the instance. In addition, ARC frees the memory of an instance when it is no longer needed, freeing the memory for other purposes. This ensures that the class instance does not occupy memory all the time when it is not needed. However, if ARC frees instance memory in use, it will not access the instance’s properties or call its methods. Indeed, if you try to access the instance, your app will probably crash. To ensure that instances in use do not disappear, ARC tracks and counts how many properties, constants, and variables the current instance is referenced by. ARC will not release an instance of the class as long as there is a reference to it. To make this possible, whenever you assign an instance to a property, constant, or variable, they create a strong reference to that instance. It is called a “strong” reference because it holds the instance, and the instance is not allowed to be destroyed as long as the strong reference exists.
ARC
The following example shows how automatic reference counting works. This example starts with a simple Person class that defines a stored constant property named name:
class Person {
let name: String
init(name: String) {
self.name = name
print(" \ (name)isBeing an initialized ")}deinit {
print(" \ (name)isBeing deinitialized ")}}Copy the code
The Person class defines an initializer and a de-initializer to print information.
The following code snippet defines three Perosons? Type to set multiple references to the new Person instance in the order in the code. Since variables of optional types are automatically initialized to nil, no reference is currently made to instances of the Person class meaning that this definition does not generate reference counts.
var reference1: Person?
var reference2: Person?
var reference3: Person?
Copy the code
You can create a new Person instance and assign it to one of the variables:
reference1 = Person(the name:"John Appleseed").* / /Prints"John Appleseed isBeing an initialized"*
Copy the code
Notice that when the initializer of the Person class is called, the message “John Appleseed is being Initialized” is printed. This means that the initial execution is done.
Because the Person instance has been assigned to the reference1 variable, you now have a strong reference from reference1 to the instance. Because there is at least one strong reference, ARC can ensure that the Person remains in memory at all times without being destroyed.
If you assign the same Person instance to two variables, the instance will have two more strong references:
reference2 = reference1
reference3 = reference1
Copy the code
This single Person instance now has three strong references.
If you break two strong references by assigning nil to two of the variables, leaving only one strong reference, the Person instance will not be destroyed:
reference1 = nil
reference2 = nil
Copy the code
ARC destroys the Person instance until the third and last strong reference is broken when you make it clear that you are no longer using it.
reference3 = nil
* / /Prints"John Appleseed isBeing deinitialized"*
Copy the code
Cyclic strong references between class instances
This is a long paragraph to summarize: instances holding each other creates circular strong references, and null variables cannot break strong references. To understand this, you can skip the following.
It is possible to write code in which a class never becomes a zero-strong reference.
This can happen if two class instances hold strong references to each other, so that each instance keeps the other alive. This is known as circular strong references.
To solve the problem of circular strong references, you can replace strong references by defining the relationship between classes as weak or unreferenced (unowned).
example
The following example shows an example of how to accidentally create a circular strong reference. This example defines two classes, Person and Apartment, to model the Apartment and its inhabitants:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print(" \ (name)isBeing deinitialized ")}}class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) isBeing deinitialized ")}}Copy the code
Each Person instance has a property of type String named name and an optional Apartment property initialized to nil. The Apartment property is optional, as one does not always own the apartment.
Similarly, each Apartment instance has a property called Unit, of type String, and an optional tenant property initialized to nil. The Tenant property is optional because an apartment does not always have residents.
Both classes define de-initializers that output information when the class instance is released. This lets you know if the Instances of Person and Apartment have been released as expected.
Define variables and assign values to them:
var John: Person?
var unit4A: Apartment?
John = Person(the name:"John Appleseed") unit4A= Apartment(unit: "4 a")Copy the code
Reference relation:
Assignment,! Used to expand access options
John! .apartment= unit4A
unit4A!.tenant = John
Copy the code
And then it becomes thetaEach other
Strong references:
The association of the two instances produces a circular strong reference.
The Person instance now has a strong reference to the Apartment instance, and the Apartment instance now has a strong reference to the Person instance. Therefore, when you disconnect strong references held by John and unit4A variables, the reference count is not reduced to zero and the instance is not freed by ARC:
John = nil
unit4A = nil
Copy the code
When we set these two variables to nil, none of the de-initializers are called. Circular strong references keep preventing the release of instances of the Person and Apartment classes, creating a memory leak in your application. After we assign John and unit4A to nil, the strong reference relationship is shown as follows:
The strong reference relationship between the Person and Apartment instances is preserved and will not be disconnected.
Breaks circular strong references between instances
Swift provides two ways to solve the problem of circular strong references when using attributes of a class: weak references and undirected references (unowned reference).
Weak and undirected references allow one instance of a circular reference to refer to another instance without maintaining a strong reference. In this way instances can refer to each other without creating circular strong references.
A weak reference
A weak reference does not maintain a strong reference to the instance it references, and thus does not prevent ARC from releasing the referenced instance. This feature prevents references from becoming circular strong references. When declaring an attribute or variable, prefix it with the weak keyword to indicate a weak reference. Since a weak reference does not strongly retain a reference to the instance, it is possible that the instance was freed and the weak reference still refers to the instance. Therefore, ARC automatically sets weak references to nil when the referenced instance is freed. Since weak references need to allow their value to be nil, they must be of optional type. You can check for weakly referenced values, just like any other optional value, and you will never encounter “wild Pointers”.
The property observer is not called when ARC sets nil for weak references.
example
The following example is the same as the Person and Apartment examples above, but with one important difference. This time, Apartment’s tenant property is declared as weak reference:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print(" \ (name)isBeing deinitialized ")}}class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) isBeing deinitialized ")}}Copy the code
Strong references and associations between two variables (John and unit4A) are created the same as last time:
var John: Person?
var unit4A: Apartment?
John = Person(the name:"John Appleseed") unit4A= Apartment(unit: "4 a")John! .apartment= unit4A
unit4A!.tenant = John
Copy the code
Now, the reference relationship between the two linked instances is shown below:
Break the strong reference to the John variable and the Person object is freed:
John = nil
* / /Prints"John Appleseed isBeing deinitialized"*
Copy the code
All that remains is a strong reference to the Apartment instance from the unit4A variable. Interrupt the strong reference again, and the Apartment instance will no longer have a strong reference:
unit4A = nil
* / /Prints"Apartment 4A isBeing deinitialized"*
Copy the code
There is no strong reference to the Apartment instance, which is freed:
Conclusion: When the last strong reference is broken, the object is released
No primary reference
Like weak references, an ownerless reference does not hold the referenced instance firmly. But unlike weak references, in short, an ownerless reference is assumed to always have a value. Therefore, an ownerless reference is always defined as a non-optional type. You can declare an attribute or variable before the keyword unowned to indicate that it is an ownerless reference.
Since an undirected reference is a non-optional type, you don’t need to expand it when you use it. An ownerless reference is always directly accessible. ARC cannot, however, set an unclaimed reference to nil after the instance is freed, because variables of non-optional types are not allowed to be assigned nil.
If you try to access an unreferenced reference whose instance has been freed, Swift will ensure that the program crashes.
example
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print(" \ (name)isBeing deinitialized ")}}class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64.customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) isBeing deinitialized ")}}Copy the code
Define an optional Customer variable that is declared optional and therefore initialized to nil
var John: Customer?
Copy the code
Initialize a Customer instance and assign a new CreditCard instance as the card attribute of Customer:
John = Customer(the name:"John Appleseed").John! .card= CreditCard(number: 1234 _5678_9012_3456Customer:John!).Copy the code
Now the Customer instance has a strong reference to the CreditCard instance, and the CreditCard instance has an undirected reference to the Customer instance.
Disconnect the reference to the John variable
John = nil
* / /Prints"John Appleseed isBeing deinitialized"*
* / /Prints"Card #1234567890123456 isBeing deinitialized"*
Copy the code
Due to theCustomer
theNo primary reference
When you disconnectjohn
variable-heldStrong reference
, then there is no point anymoreCustomer
A strong reference to an instance,Customer
The instance will be released, and thenCreditCard
The instance is also released.
Unsafe ownerless reference
The use of unowned(unsafe) explicitly uses an unsafe and ownerless reference. If you access an unsafe reference after the instance’s reference has been freed, your program will attempt to access the memory address where the instance once existed, which is an unsafe operation.
No master optional reference
You can mark a class with an optional reference as an undirected reference. From an ARC ownership model perspective, an ownerless optional reference and a weak reference can be used in the same context. The difference is when you use an ownerless optional reference, you’re responsible for making sure it always refers to a legitimate object or nil.
Example:
unowned var nextCourse: Course?
Copy the code
An ownoptional reference does not keep a strong reference to the object it contains, so it does not prevent ARC from releasing the instance. It behaves like an ownerless reference under ARC, except that an ownerless optional reference can be nil.
Optional properties for no main reference and implicit expansion
var capitalCity: City!
Copy the code
By adding an exclamation point at the end of the type City! To declare the Country’s capitalCity property as an implicitly expanded optional property. The capitalCity property has a default value of nil, but it can be accessed without expanding its value.
You can create instances of both Country and City in a single statement without cyclic strong references, and capitalCity properties can be accessed directly without the need for an exclamation point to expand its optional values:
var country = Country(the name:"Canada, "capitalName."Ottawa").print(" \ (country name) 's capital cityisCalled \ (country) capitalCity) name) ").* / /Prints"Canada's capital cityis called Ottawa"*
Copy the code
In the example above, the point of using the optional attribute of implicit expansion is to satisfy the need for a two-stage initializer. Once the capitalCity property is initialized, it can be used and accessed as if it were not optional, while avoiding circular strong references.
Circular strong references to closures
Circular strong references can occur between closures and instances.
Swift provides an elegant way to solve this problem, called the Closuer Capture List.
example
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return “<\ [self.name)>\(text)</\ [self.name)>"}else {
return “<\ [self.name) />"}}init(name: String.text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print(" \ (name)isBeing deinitialized ")}}Copy the code
Instantiation:
var paragraph: HTMLElement? = HTMLElement(name: “p”, text: “hello, world”)
print(paragraph!.asHTML())
* / /Prints "hello, world"*
Copy the code
The closure uses self inside its closure (referencing self.name and self.text), so the closure captures self, which means that the closure in turn holds a strong reference to the HTMLElement instance. This creates a circular strong reference between the two objects.
If the paragraph variable is set to nil, this loop of strong references cannot be broken, and neither the closure nor the instance is released:
paragraph = nil
Copy the code
Resolve circular strong references to closures
Defining a capture list
Each item in the capture list consists of the weak or unowned keyword with a reference to a class instance (such as self) or initialized variables (such as delegate = self.delegate!). In pairs. These terms are written in square brackets separated by commas. Place the capture list before the formal parameters and return types, if they exist:
lazy var someClosure: (Int.String) - >String ={[unowned self.weak delegate = self.delegate!] (index: Int, stringToProcess: String) - >String in
* / / closure body goes here*
}
Copy the code
If the closure does not specify formal argument lists or return types because they are inferred from context, place the capture list before the keyword in, at the beginning of the closure:
lazy var someClosure: () -> String ={[unowned self.weak delegate = self.delegate!] in
* / / closure body goes here*
}
Copy the code
Weak and undirected references
If the captured reference never becomes nil, use an ownerless reference rather than a weak reference. In the previous HTMLElement example, an undirected reference was the correct way to deal with circular strong references. The HTMLElement class is written like this to avoid circular strong references:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String ={[unowned self] in
if let text = self.text {
return “<\ [self.name)>\(text)</\ [self.name)>"}else {
return “<\ [self.name) />"}}init(name: String.text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print(" \ (name)isBeing deinitialized ")}}Copy the code
The HTMLElement implementation above is the same as the previous implementation, except for the addition of a capture list in the asHTML closure. Here, the capture list is [unowned self], which means “capture self with an undirected reference instead of a strong reference.” As before, we can create and print an HTMLElement instance:
var paragraph: HTMLElement? = HTMLElement(name: “p”, text: “hello, world”)
print(paragraph!.asHTML())
* / /Prints"<p>hello, world</p>"*
Copy the code
useCapture the list
The post-reference relationship is shown in the figure below:This time, closures are captured as ownerless referencesself
They don’t holdHTMLElement
A strong reference to an instance. If you haveparagraph
The assignment fornil
, HTMLElement
The instance will be released and can see itsAnti-initializer
A printed message.
paragraph = nil
* / /Prints "pisBeing deinitialized"*
Copy the code