-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathARC
200 lines (160 loc) · 10.1 KB
/
ARC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
Automatic Reference Counting (ARC)
Model the lifetime of objects and their relationships.
1. What is ARC?
Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage.
Reference counting applies only to the classes.
Structures and enumerations are value types, not reference types, and aren’t stored and passed by reference.
2. How ARC works?
Whenever you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance. This memory
holds information about the type of the instance, together with the values of any stored properties associated with that instance.
When an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purpose instead.
This ensures that class instances don’t take up space in memory when they’re no longer needed.
To make sure that instances don't disappear while they're still in use, ARC tracks how many properties, constants, and variables are currently
referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant,
or variable makes a strong reference to the instance. The reference is called a “strong” reference because it keeps a firm hold on that instance,
and doesn’t allow it to be deallocated for as long as that strong reference remains.
3. What is Strong Reference Cycle?
If two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a Strong Refernce Cycle.
4. How do you resolve a strong reference cycle?
You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references
instead of strong refrences.
5. Explain how weak or unowned reference handles the memory leak?
Weak and unowned references enable one instance in a refernce cycle to refer to the other instance without keeping a strong hold on it.
The instances can then refer to each other without creating a strong reference cycle.
6. When should use Weak reference?
Use a weak reference when the other instance has a short lifetime - that is, when the other instance can be deallocated first.
Because a weak reference doesn’t keep a strong hold on the instance it refers to,
it’s possible for that instance to be deallocated while the weak reference is still referring to it.
Therefore, ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated.
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
it’s appropriate for an apartment to be able to have no tenant at some point in its lifetime,
and so a weak reference is an appropriate way to break the reference cycle in this case.
7. Why weak reference is always variable?
Weak references need to allow their value to be changed to nil at runtime, they’re always declared as variables,
rather than constants, of an optional type.
6. When should use Unowned reference?
Like a weak reference, an unowned reference doesn’t keep a strong hold on the instance it refers to. Unlike a weak reference,
however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime.
You indicate an unowned reference by placing the unowned keyword before a property or variable declaration.
Unlike a weak reference, an unowned reference is expected to always have a value.
As a result, marking a value as unowned doesn’t make it optional, and ARC never sets an unowned reference’s value to nil.
For example:
Customer and Credit Card
Customer may not have a credit card
But
Credit card will always be associated with a customer.
A CreditCard instance never outlives the Customer that it refers to.
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being 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) is being deinitialized") }
}
The Customer and CreditCard example shows a situation where one property that’s allowed to be nil and another property that can’t be nil
have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.
7. What is unsafe unowned reference?
You indicate an unsafe unowned reference by writing unowned(unsafe).
If you try to access an unsafe unowned reference after the instance that it refers to is deallocated,
your program will try to access the memory location where the instance used to be, which is an unsafe operation.
8. What is unowned optional reference?
You can mark an optional reference to a class as unowned. In terms of the ARC ownership model,
an unowned optional reference and a weak reference can both be used in the same contexts.
The difference is that when you use an unowned optional reference,
you’re responsible for making sure it always refers to a valid object or is set to nil.
both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario,
it’s useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.
9. How strong reference cycles for closures created?
A strong reference cycle can also occure if you assign a closure to a property of a class instance, and the body of that closure captures the
instance. This capture might occur because the closure’s body accesses a property of the instance, such as self.someProperty,
or because the closure calls a method on the instance, such as self.someMethod().
In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle.
This strong reference cycle occurs because closures, like classes, are reference types.
When you assign a closure to a property, you are assigning a reference to that closure.
In essence, it’s the same problem as above — two strong references are keeping each other alive.
you can create a strong reference cycle when using a closure that references self.
10. What is capture list in the Closure
Swift provides a solution to resolve closure strong reference cycle that is closure capture list.
11. How do you resolve the strong reference cycles for closures
You resolve a strong reference cycle between closure and a class instance by defining a capture list as part of the closure's definition.
A capture list defines the rules to use when capturing one or more reference types within the closure’s body.
As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference.
12. How do you define the capture list?
Each item in a capture list is a pairing of the weak or unowned keyword with a reference to a class instance (such as self)
or a variable initialized with some value (such as delegate = self.delegate).
These pairings are written within a pair of square braces, separated by commas.
Place the capture list before a closure’s parameter list and return type if they’re provided:
lazy var someClosure = {
[unowned self, weak delegate = self.delegate]
(index: Int, stringToProcess: String) -> String in
// closure body goes here
}
If a closure doesn’t specify a parameter list or return type because they can be inferred from context,
place the capture list at the very start of the closure, followed by the in keyword:
lazy var someClosure = {
[unowned self, weak delegate = self.delegate] in
// closure body goes here
}
13. When should be define Unowned reference in closure?
Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other,
and will always be deallocated at the same time.
If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference.
14. When should be define weak reference in closure?
Define a capture as a weak reference when the captured reference may become nil at some point in the future.
Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated.
This enables you to check for their existence within the closure’s body.
15. Discuss how ARC works in Swift?
An object's lifetime in Swift begins at initialization and ends at last use.
ARC automatically manages memory, by deallocating an object after its lifetime ends.
It determines an object's lifetime by keeping track of its reference counts.
16. How you prevent retain cycle in Swift when using closure.
By defining the capture list.
18. Given an example where you would use unowned instead of weak.
Credit card and customer.
For example:
Customer and Credit Card
Customer may not have a credit card
But
Credit card will always be associated with a customer.
A CreditCard instance never outlives the Customer that it refers to.
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being 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) is being deinitialized") }
}
The Customer and CreditCard example shows a situation where one property that’s allowed to be nil and another property that can’t be nil
have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.