+ All Categories
Home > Software > Connect.Tech- Swift Memory Management

Connect.Tech- Swift Memory Management

Date post: 16-Apr-2017
Category:
Upload: stablekernel
View: 101 times
Download: 0 times
Share this document with a friend
44
Swift Memory Management By: Marcus Smith Software Engineer stable|kernel [email protected]
Transcript
Page 1: Connect.Tech- Swift Memory Management

Swift Memory ManagementBy: Marcus Smith Software Engineer stable|[email protected]

Page 2: Connect.Tech- Swift Memory Management

@stablekernel

Why should you care?

Page 3: Connect.Tech- Swift Memory Management

@stablekernel

Who am I?

• Marcus Smith • iOS Developer at stable|kernel • Struggled learning memory management • Previously worked for BMW and Frozen Fire Studios • Have a game in the app store

Page 4: Connect.Tech- Swift Memory Management

stable|kernel is an Atlanta-based mobile development company to craft smartly-designed mobile applications that connect brands directly with their users. Our team of engineers and designers takes clients from strategy through design, development and deployment, ensuring timely delivery of the highest quality applications.

Page 5: Connect.Tech- Swift Memory Management

Memory Management

@stablekernel

• Value & Reference Types • Reference Counting & ARC • Avoiding memory issues

Page 6: Connect.Tech- Swift Memory Management

Value & Reference Types

@stablekernel

• Value types contain data • Reference types contain the location in memory where data is

Page 7: Connect.Tech- Swift Memory Management

Value Types

@stablekernel

• Structs, Enums and Tuples • Copied on assignment or when passing to a function

struct Point { var x, y: Int }

let aPoint = Point(x: 0, y: 0) var anotherPoint = aPoint anotherPoint.x = 5 print(aPoint.x) // prints 0

Page 8: Connect.Tech- Swift Memory Management

Reference Types

@stablekernel

• Classes and Closures • Creates another reference when assigned to a variable or passed to a function • Implicit sharing

Page 9: Connect.Tech- Swift Memory Management

@stablekernel

class Person { var name: String var age: Int init(name: String, age: Int) {…} }

let bob = Person(name: “Bob”, age: 30) let myNeighbor = bob myNeighbor.age = 50 print(bob.age) // prints 50

func increaseAge(person: Person) { person.age += 1 }

increaseAge(person: bob) print(myNeighbor.age) // prints 51

Page 10: Connect.Tech- Swift Memory Management

Reference Types

@stablekernel

• More power, more responsibility • Can have multiple owners • Inheritance • Require some memory management on the part of the programmer

• blog.stablekernel.com

Page 11: Connect.Tech- Swift Memory Management

Reference Counting

@stablekernel

• Type of garbage collection • Objects keep a count of references • When an object’s reference count gets down to 0, it is destroyed and its

memory is freed • Used to be done manually with alloc, retain, copy, release

Page 12: Connect.Tech- Swift Memory Management

@stablekernel

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

Page 13: Connect.Tech- Swift Memory Management

Automatic Reference Counting (ARC)

@stablekernel

• Compiler makes retain and release calls • Has a problem with circular references creating retain cycles (memory leaks)

Page 14: Connect.Tech- Swift Memory Management

@stablekernel

class Person { var name: String var age: Int init(name: String, age: Int) {…} var apartment: Apartment? }

class Apartment { let unit: String init(unit: String) {…} var tenant: Person? }

class SomeViewController: UIViewController { var person: Person!

override func viewDidLoad() { super.viewDidLoad()

person = Person(name: “Bob”, age: 30) let unit4A = Apartment(unit: “4A”) person.apartment = unit4A unit4A.tenant = person } }

Page 15: Connect.Tech- Swift Memory Management

@stablekernel

UINavigationController SomeViewController

Person

Apartment

Push1

1

1

2

0Pop

Page 16: Connect.Tech- Swift Memory Management

ARC - Strong and Weak References

@stablekernel

• ARC deals with circular references by having strong and weak references • Strong references increase an object’s reference count • Weak references do not increase an object’s reference count • In Swift, references are strong by default

class Apartment { let unit: String init(unit: String) {…} var tenant: Person? }

Page 17: Connect.Tech- Swift Memory Management

ARC - Strong and Weak References

@stablekernel

• ARC deals with circular references by having strong and weak references • Strong references increase an object’s reference count • Weak references do not increase an object’s reference count • In Swift, references are strong by default

class Apartment { let unit: String init(unit: String) {…} weak var tenant: Person? }

Page 18: Connect.Tech- Swift Memory Management

@stablekernel

UINavigationController SomeViewController

Person

Apartment

Push1

1

1

0Pop

0

0

Page 19: Connect.Tech- Swift Memory Management

ARC - Weak References

@stablekernel

• Weak references help prevent retain cycles • Can go nil at any time, which was problematic in Objective-C • In Swift, weak references must be optional vars

weak var tenant: Person

weak let tenant: Person? ‘weak’ must be a mutable variable, because it may change at runtime

‘weak’ variable should have optional type ‘Person?’

Page 20: Connect.Tech- Swift Memory Management

ARC - Unowned References

@stablekernel

• Like weak references, but non-optional • Should only be used if you can guarantee the object won’t become nil • Objective-C name “Unsafe Unretained” • In Objective-C dangling pointers could cause crashes or data corruption

“Swift guarantees your app will crash if you try to access an unowned reference after the instance it references is deallocated. You will never encounter unexpected behavior in this situation. Your app will always crash reliably, although you should, of course, prevent it from doing so.”

unowned let tenant: Person

Page 21: Connect.Tech- Swift Memory Management

Avoiding Retain Cycles

@stablekernel

• Delegates • Parent - Child relationships • IBOutlets • CoreData • Closures • Lazy properties

Page 22: Connect.Tech- Swift Memory Management

Delegates

@stablekernel

• Delegates should be weak open class UITableView { weak open var dataSource: UITableViewDataSource? weak open var delegate: UITableViewDelegate? ... }

protocol SomeDelegate {}

class SomeObject { weak var delegate: SomeDelegate? } ‘weak’ may only be applied to class and class-bound

protocol types, not ‘SomeDelegate’

Page 23: Connect.Tech- Swift Memory Management

Delegates

@stablekernel

• Delegates should be weak open class UITableView { weak open var dataSource: UITableViewDataSource? weak open var delegate: UITableViewDelegate? ... }

protocol SomeDelegate: class {}

class SomeObject { weak var delegate: SomeDelegate? } ‘weak’ may only be applied to class and class-bound

protocol types, not ‘SomeDelegate’

Page 24: Connect.Tech- Swift Memory Management

Parent - Child Relationships

@stablekernel

• Parents typically should hold a strong reference to their children • Children should hold a weak reference to their parent

extension UIView { open var superview: UIView? { get } open var subviews: [UIView] { get } ... }

open class UIViewController { weak open var parent: UIViewController? { get } open var childViewControllers: [UIViewController] { get } ... }

Page 25: Connect.Tech- Swift Memory Management

IBOutlets

@stablekernel

• Weak by default (except root view) • Retained by superviews • Need to be declared as strong if you will be removing and re-adding • Same is true for NSLayoutConstraint

Page 26: Connect.Tech- Swift Memory Management

@stablekernel

class ViewController: UIViewController { @IBOutlet weak var someView: UIView! /// A subview of `someView` @IBOutlet weak var someSubView: UIView! override func viewDidLoad() { super.viewDidLoad() someView.removeFromSuperview() }

override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) someSubView.backgroundColor = .red }}

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

fatal error: unexpectedly found nil while unwrapping an Optional value

Page 27: Connect.Tech- Swift Memory Management

@stablekernel

class ViewController: UIViewController { @IBOutlet var someView: UIView! /// A subview of `someView` @IBOutlet weak var someSubView: UIView! override func viewDidLoad() { super.viewDidLoad() someView.removeFromSuperview() }

override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) someSubView.backgroundColor = .red }}

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

fatal error: unexpectedly found nil while unwrapping an Optional value

Page 28: Connect.Tech- Swift Memory Management

Core Data

@stablekernel

• CoreData relationships on NSManagedObjects create retain cycles • To break these retain cycles call refresh on NSManagedObjectContext:

context.refresh(someManagedObject, mergeChanges: false)

Page 29: Connect.Tech- Swift Memory Management

Closures

@stablekernel

• Blocks of code that can be passed around

let sayHello: (String) -> Void = { name in print("Hello \(name)") } sayHello("World") // prints "Hello World”

let add: (Int, Int) -> Int = { x, y in return x + y } let total = add(3, 5) // returns 8

let numbers = [1, 2, 3, 4, 5] let odds = numbers.filter { number in return number % 2 == 1 } print(odds) // prints [1, 3, 5]

Page 30: Connect.Tech- Swift Memory Management

Closures

@stablekernel

• Reference type • Have to capture and store references to the variables they need to run

let increaseBobsAgeBy: (Int) -> Void = { (value) in bob.age += value }

class Executable { let bob: Person init(bob: Person) {…} func execute(value: Int) { bob.age += value } }

increaseBobsAgeBy(2)

Page 31: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomething() {…} func makeNetworkRequest() {…} func update() { completion = { doSomething() } makeNetworkRequest() } }

Call to method ‘doSomething’ in closure requires explicit ‘self.’ to make capture semantics explicit

Page 32: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomething() {…} func makeNetworkRequest() {…} func update() { completion = { self.doSomething() } makeNetworkRequest() } }

Call to method ‘doSomething’ in closure requires explicit ‘self.’ to make capture semantics explicit

• Closures require an explicit self • Can cause retain cycles if an object owns a closure that captures itself

Page 33: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomething() {…} func update() { completion = { self.doSomething() } } } class Executable { let someClass: SomeClass init(someClass: SomeClass) {…} func execute() { someClass.doSomething() } }

Page 34: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomething() {…} func update() { completion = { [weak self] in self.doSomething() } } } class Executable { let someClass: SomeClass init(someClass: SomeClass) {…} func execute() { someClass.doSomething() } }

Page 35: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomething() {…} func update() { completion = { [weak self] in self.doSomething() } } } class Executable { weak var someClass: SomeClass? init(someClass: SomeClass) {…} func execute() { someClass.doSomething() } }

Page 36: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomething() {…} func update() { completion = { [weak self] in self?.doSomething() } } } class Executable { weak var someClass: SomeClass? init(someClass: SomeClass) {…} func execute() { someClass?.doSomething() } }

Page 37: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomethingWithNonOptional(_ someClass: SomeClass) {…} func update() { completion = { [weak self] in } } }

Page 38: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomethingWithNonOptional(_ someClass: SomeClass) {…} func update() { completion = { [unowned self] in doSomethingWithNonOptional(self) } } }

Page 39: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomethingWithNonOptional(_ someClass: SomeClass) {…} func update() { completion = { [weak self] in if let strongSelf = self { doSomethingWithNonOptional(strongSelf) } } } }

Page 40: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

class SomeClass { var completion: () -> Void func doSomethingWithNonOptional(_ someClass: SomeClass) {…} func update() { completion = { [weak self] in guard let strongSelf = self else { return } doSomethingWithNonOptional(strongSelf) } } }

Page 41: Connect.Tech- Swift Memory Management

Closures - Capturing Self

@stablekernel

• Self does not always need to be captured weakly • Depends on what objects may own the closure with self

DispatchQueue.main.async { self.doSomething() // Not a retain cycle }

UIView.animate(withDuration: 1) { self.doSomething() // Not a retain cycle }

DispatchQueue.main.asyncAfter(deadline: .now() + 30) { self.doSomething() // Not a retain cycle, but... }

Page 42: Connect.Tech- Swift Memory Management

Lazy Properties

@stablekernel

• Lazy closure properties need to capture self weakly to prevent retain cycles

class Person { lazy var greeting: () -> String = { [unowned self] in return “Hi, I’m \(self.name)” } }

class Person { lazy var fullName: String = { return “\(self.firstName) \(self.lastName)” }() }

• Other lazy properties do not

Page 43: Connect.Tech- Swift Memory Management

Avoiding Retain Cycles

@stablekernel

• Delegates - delegate should be weak • Parent - Child relationships - parent property should be weak • IBOutlets - weak or strong is fine, but strong if removing and re-adding • CoreData - refresh changes to turn back into faults • Closures - be careful what you capture and how • Lazy properties - only need to capture self weakly for closure properties

Page 44: Connect.Tech- Swift Memory Management

Questions?

Business Inquiries: Sarah Woodward Director of Business Development [email protected]

Marcus Smith Software Engineer [email protected] blog.stablekernel.com


Recommended