KEMBAR78
Automatic reference counting in Swift | PDF
Automatic Reference
Counting
Allan Shih
Agenda
● Overview
● Strong Reference Cycles Between Class Instances
● Resolving Strong Reference Cycles
○ Weak references
○ Unowned references
● Strong Reference Cycles for Closures
● Reference
Overview
● Method for managing memory
● Different from garbage collection
● Used in both iOS and OS X
● Counts “Strong” References to an object
● The OS releases the memory when the reference count has reached zero
● Adding to and Subtracting from the count is handled by the compiler
ARC in Action
class Person {
let name: String
init(name: String) {
self.name = name
print("(name) is being initialized")
}
deinit {
print("(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"
reference2 = reference1
reference3 = reference1
reference1 = nil
reference2 = nil
reference3 = nil
// Prints "John Appleseed is being deinitialized"
Strong Reference Cycles Between Class Instances
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
}
var tenant: Person?
deinit {
print("Apartment (unit) is being
deinitialized")
}
}
Strong Reference Cycles Between Class Instances
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
Link the two instances together
john!.apartment = unit4A
unit4A!.tenant = john
Strong reference cycle
john = nil
unit4A = nil
Resolving Strong Reference Cycles
Swift provides two ways to resolve strong reference cycles when you work with
properties of class type:
● Weak references
○ It is valid for that reference to become nil at some point during its lifetime.
● Unowned references
○ You know that the reference will never be nil once it has been set during initialization.
Weak References
A weak reference is a reference that does not keep a strong hold on the
instance it refers to, and so does not stop ARC from disposing of the
referenced instance.
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")
}
}
Weak References
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
Weak References
john = nil
// Prints "John Appleseed is being deinitialized"
Weak References
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
Unowned References
An unowned reference does not keep a strong hold on the instance it refers to, it is expected to always
have a value.
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") }
}
Unowned References
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
Unowned References
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"
Different between Weak and Unowned
A weak reference is always optional and automatically becomes nil when the
referenced object deinitializes.
var let Optional Non-Optional
Strong V V V V
Weak V X V X
Unowned V V X V
Unowned References and Implicitly Unwrapped Optional Properties
Country and City, each of which stores an instance of the other class as a
property.
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String)
{
self.name = name
self.capitalCity = City(name:
capitalName, country: self)
}
}
class City {
let name: String
unowned let country: Country
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
Unowned References and Implicitly Unwrapped Optional Properties
var country = Country(name: "Taiwan", capitalName: "Taipei")
print("(country.name)'s capital city is called (country.capitalCity.name)")
// Prints "Taiwan's capital city is called Taipei"
<Country instance>
name: “Taiwan”
capitalCity: <City instance>
<City instance>
name: “Taipei”
country: <Country instance>
Strong
Unowned
var country
Strong
Strong Reference Cycles for Closures
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) is being deinitialized")
}
Strong Reference Cycles for Closures
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"
Strong Reference Cycles for Closures
paragraph = nil
Defining a Closure Capture List
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess:
String) -> String in
// closure body goes here
}
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
Defining a Closure Capture List
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) is being deinitialized")
}
Defining a Closure Capture List
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"
Reference
● The Swift Programming Language (Swift 3.0.1)

Automatic reference counting in Swift

  • 1.
  • 2.
    Agenda ● Overview ● StrongReference Cycles Between Class Instances ● Resolving Strong Reference Cycles ○ Weak references ○ Unowned references ● Strong Reference Cycles for Closures ● Reference
  • 3.
    Overview ● Method formanaging memory ● Different from garbage collection ● Used in both iOS and OS X ● Counts “Strong” References to an object ● The OS releases the memory when the reference count has reached zero ● Adding to and Subtracting from the count is handled by the compiler
  • 4.
    ARC in Action classPerson { let name: String init(name: String) { self.name = name print("(name) is being initialized") } deinit { print("(name) is being deinitialized") } } var reference1: Person? var reference2: Person? var reference3: Person? reference1 = Person(name: "John Appleseed") // Prints "John Appleseed is being initialized" reference2 = reference1 reference3 = reference1 reference1 = nil reference2 = nil reference3 = nil // Prints "John Appleseed is being deinitialized"
  • 5.
    Strong Reference CyclesBetween Class Instances 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 } var tenant: Person? deinit { print("Apartment (unit) is being deinitialized") } }
  • 6.
    Strong Reference CyclesBetween Class Instances var john: Person? var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A")
  • 7.
    Link the twoinstances together john!.apartment = unit4A unit4A!.tenant = john
  • 8.
    Strong reference cycle john= nil unit4A = nil
  • 9.
    Resolving Strong ReferenceCycles Swift provides two ways to resolve strong reference cycles when you work with properties of class type: ● Weak references ○ It is valid for that reference to become nil at some point during its lifetime. ● Unowned references ○ You know that the reference will never be nil once it has been set during initialization.
  • 10.
    Weak References A weakreference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. 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") } }
  • 11.
    Weak References var john:Person? var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A") john!.apartment = unit4A unit4A!.tenant = john
  • 12.
    Weak References john =nil // Prints "John Appleseed is being deinitialized"
  • 13.
    Weak References unit4A =nil // Prints "Apartment 4A is being deinitialized"
  • 14.
    Unowned References An unownedreference does not keep a strong hold on the instance it refers to, it is expected to always have a value. 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") } }
  • 15.
    Unowned References var john:Customer? john = Customer(name: "John Appleseed") john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
  • 16.
    Unowned References john =nil // Prints "John Appleseed is being deinitialized" // Prints "Card #1234567890123456 is being deinitialized"
  • 17.
    Different between Weakand Unowned A weak reference is always optional and automatically becomes nil when the referenced object deinitializes. var let Optional Non-Optional Strong V V V V Weak V X V X Unowned V V X V
  • 18.
    Unowned References andImplicitly Unwrapped Optional Properties Country and City, each of which stores an instance of the other class as a property. class Country { let name: String var capitalCity: City! init(name: String, capitalName: String) { self.name = name self.capitalCity = City(name: capitalName, country: self) } } class City { let name: String unowned let country: Country init(name: String, country: Country) { self.name = name self.country = country } }
  • 19.
    Unowned References andImplicitly Unwrapped Optional Properties var country = Country(name: "Taiwan", capitalName: "Taipei") print("(country.name)'s capital city is called (country.capitalCity.name)") // Prints "Taiwan's capital city is called Taipei" <Country instance> name: “Taiwan” capitalCity: <City instance> <City instance> name: “Taipei” country: <Country instance> Strong Unowned var country Strong
  • 20.
    Strong Reference Cyclesfor Closures 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) is being deinitialized") }
  • 21.
    Strong Reference Cyclesfor Closures var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") print(paragraph!.asHTML()) // Prints "<p>hello, world</p>"
  • 22.
    Strong Reference Cyclesfor Closures paragraph = nil
  • 23.
    Defining a ClosureCapture List lazy var someClosure: (Int, String) -> String = { [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in // closure body goes here } lazy var someClosure: () -> String = { [unowned self, weak delegate = self.delegate!] in // closure body goes here }
  • 24.
    Defining a ClosureCapture List 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) is being deinitialized") }
  • 25.
    Defining a ClosureCapture List var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") print(paragraph!.asHTML()) // Prints "<p>hello, world</p>"
  • 26.
    Reference ● The SwiftProgramming Language (Swift 3.0.1)