Memory Management - Cocoa - iOS 8 Programming Fundamentals with Swift: Swift, Xcode, and Cocoa Basics (2015)

iOS 8 Programming Fundamentals with Swift: Swift, Xcode, and Cocoa Basics (2015)

Part III. Cocoa

Chapter 12. Memory Management

Class instances, both in Swift and in Objective-C, are reference types (see Value Types and Reference Types). Behind the scenes, Swift and Objective-C memory management for reference types works essentially the same way. Such memory management, as I pointed out in Chapter 5, can be a tricky business.

Fortunately, Swift uses ARC (automatic reference counting), so that you don’t have to manage the memory for every reference type object explicitly and individually, as was once necessary in Objective-C. Thanks to ARC, you are far less likely to make a memory management mistake, and more of your time is liberated to concentrate on what your app actually does instead of dealing with memory management concerns.

But even with ARC it is still possible to make a memory management mistake, or to be caught unawares by Cocoa’s memory management behavior. A memory management mistake can lead to runaway excessive memory usage, crashes, or mysterious misbehavior of your app, and even in Swift it is possible to make such a mistake. Cocoa memory management can be surprising in individual cases, and you need to understand, and prepare for, what Cocoa is going to do.

Principles of Cocoa Memory Management

The reason why reference type memory must be managed at all is that references to reference type objects are merely pointers. The real object pointed to occupies a hunk of memory that must be explicitly set aside when the object is brought into existence and that must be explicitly freed up when the object goes out of existence. The memory is set aside when the object is instantiated, but how is this memory to be freed up, and when should it happen?

At the very least, an object should certainly go out of existence when no other objects exist that have a pointer to it. An object without a pointer to it is useless; it is occupying memory, but no other object has, or can ever get, a reference to it. This is a memory leak. Many computer languages solve this problem through a policy called garbage collection. Simply put, the language prevents memory leaks by periodically sweeping through a central list of all objects and destroying those to which no pointer exists. But garbage collection would be an expensive strategy on an iOS device, where memory is strictly limited and the processor is relatively slow (and may have only a single core). Thus, memory in iOS must be managed more or less manually, on an individual basis; each object needs to go out of existence exactly when it is no longer needed.

The hard part in that sentence is the word “exactly.” An object must go out of existence neither too late nor too soon. Multiple objects can have a pointer (a reference) to the very same object. If both the object Manny and the object Moe have a pointer to the object Jack, and if Manny somehow tells Jack to go out of existence now, poor old Moe is left with a pointer to nothing (or worse, to garbage). A pointer whose object has been destroyed behind the pointer’s back is a dangling pointer. If Moe subsequently uses that dangling pointer to send a message to the object that it thinks is there, the app will crash.

To prevent both dangling pointers and memory leakage, there is a policy of manual memory management based on a number, maintained by every reference type object, called its retain count. The rule is that other objects can increment or decrement an object’s retain count — and that’s all they are allowed to do. As long as an object’s retain count is positive, the object will persist. No object has the direct power to tell another object to be destroyed; rather, as soon as an object’s retain count is decremented to zero, it is destroyed automatically.

By this policy, every object that needs Jack to persist should increment Jack’s retain count, and should decrement it once again when it no longer needs Jack to persist. As long as all objects are well-behaved in accordance with this policy, the problem of manual memory management is effectively solved:

§ There cannot be any dangling pointers, because any object that has a pointer to Jack has incremented Jack’s retain count, thus ensuring that Jack persists.

§ There cannot be any memory leaks, because any object that no longer needs Jack decrements Jack’s retain count, thus ensuring that eventually Jack will go out of existence (when the retain count reaches zero, indicating that no object needs Jack any longer).

Rules of Cocoa Memory Management

An object is well-behaved with respect to memory management as long as it adheres to certain very simple, well-defined rules in conformity with the basic concepts of memory management. The underlying ethic is that each object that has a reference to a reference type object is responsible solely for its own memory management of that object, in accordance with these rules. If all objects that ever get a reference to this reference type object behave correctly with respect to these rules, the object’s memory will be managed correctly and it will go out of existence exactly when it is no longer needed.

Consider three objects: Manny, Moe, and Jack. Poor old Jack is going to be the victim here: we’re going to manage his memory, and if Jack’s memory is managed correctly, Jack will go out of existence correctly. Manny and Moe are going to participate in managing in Jack’s memory. How will they do that? Everything will be fine as long as Manny and Moe follow these rules:

§ If Manny or Moe explicitly instantiates Jack — by directly calling an initializer — then the initializer increments Jack’s retain count.

§ If Manny or Moe makes a copy of Jack — by calling copy or copyWithZone: or mutableCopy or any other method with copy in its name — then the copy method increments the retain count of this new, duplicate Jack.

§ If Manny or Moe acquires a reference to Jack (not through explicit instantiation or copying), and needs Jack to persist — long enough to work with Jack in code, or long enough to be the value of an instance property — then he himself increments Jack’s retain count. (This is calledretaining Jack.)

§ If and only if Manny or Moe, himself, has done any of those things — that is, if Manny or Moe has ever directly or indirectly caused Jack’s retain count to be incremented — then when he himself no longer needs his reference to Jack, before letting go of that reference, he decrementsJack’s retain count to balance exactly all previous increments that he himself has performed — and he should then assume that Jack no longer exists, because if this causes Jack’s retain count to drop to zero, Jack will no longer exist. (This is called releasing Jack.) This is the golden rule of memory management — the rule that makes memory management work coherently and correctly.

A general way of understanding the golden rule of memory management is to think in terms of ownership. If Manny has created, copied, or retained Jack — that is, if Manny has ever incremented Jack’s retain count — Manny has asserted ownership of Jack. Both Manny and Moe can own Jack at once, but each is responsible only for managing his own ownership of Jack correctly. It is the responsibility of an owner of Jack eventually to decrement Jack’s retain count — to release Jack, thus resigning ownership of Jack. The owner thus says: “Jack may or may not persist after this, but as for me, I’m done with Jack, and Jack can go out of existence as far as I’m concerned.” At the same time, a nonowner of Jack must never release Jack. As long as all objects that ever take ownership of Jack behave this way, Jack will not leak nor will any pointer to Jack be left dangling.

What ARC Is and What It Does

Once upon a time, retaining and releasing an object was a matter of you, the programmer, literally sending retain and release messages to it. NSObject still implements retain and release, but under ARC (and in Swift) you can’t call them. That’s because ARC is calling them for you! That’s ARC’s job — to do for you what you would have had to do if memory management were still up to the programmer.

ARC is implemented as part of the compiler. The compiler is literally modifying your code by inserting retain and release calls behind the scenes. Thus, for example, when you receive a reference type object by calling some method, ARC immediately retains it so that it will persist for as long as this same code continues to run; then ARC releases it when the code comes to an end. Similarly, when you create or copy a reference type object, ARC knows that its retain count has been incremented, and releases it when the code comes to an end.

ARC is very conservative, but also very accurate. In effect, ARC retains at every juncture that might have the slightest implications for memory management: it retains when an object is received as an argument, it retains when an object is assigned to a variable, and so forth. It may even insert temporary variables, behind the scenes, to enable it to refer sufficiently early to an object so that it can retain it. But of course it eventually also releases to match.

How Cocoa Objects Manage Memory

Built-in Cocoa objects will take ownership of objects that you hand to them, by retaining them, if it makes sense for them to do so, and will of course then balance that retain with a release later. Indeed, this is so generally true that if a Cocoa object is not going to retain an object you hand it, there will be a note to that effect in the documentation. A collection, such as an NSArray or an NSDictionary, is a particularly obvious case in point (see Chapter 10 for a discussion of the common collection classes).

An object can hardly be an element of a collection if that object can go out of existence at any time; so when you add an element to a collection, the collection asserts ownership of the object by retaining it. Thereafter, the collection acts as a well-behaved owner. If this is a mutable collection, then if an element is removed from it, the collection releases that element. If the collection object goes out of existence, it releases all its elements.

Prior to ARC, removing an object from a mutable collection constituted a potential trap. Consider the following Objective-C code:

NSString* s = myMutableArray[0];

[myMutableArray removeObjectAtIndex: 0]; // bad idea in non-ARC code!

// ... could crash here by referring to s ...

As I just said, when you remove an object from a mutable collection, the collection releases it. So the commented line of code in the previous example involves an implicit release of the object that used to be element 0 of myMutableArray. If this reduces the object’s retain count to zero, it will be destroyed. The pointer s will then be a dangling pointer, and a crash may be in our future when we try to use it as if it were a real object.

With ARC, however, that sort of danger doesn’t exist. Assigning a reference type object to a variable retains it! Thus that code is perfectly safe, and so is its Swift equivalent:

let s = myMutableArray[0]

myMutableArray.removeObjectAtIndex(0)

// ... safe to refer to s ...

The first line retains the object. The second line releases the object, but that release balances the retain that was placed on the object when the object was placed in the collection originally. Thus the object’s retain count is still more than zero, and it continues to exist for the duration of this code.

Autorelease Pool

When a method creates an instance and returns that instance, some memory management hanky-panky has to take place. For example, consider this simple code:

func makeImage() -> UIImage? {

if let im = UIImage(named:"myImage") {

return im

}

return nil

}

Think about the retain count of im, the UIImage we are returning. This retain count has been incremented by our call to the UIImage initializer UIImage(named:). According to the golden rule of memory management, as we pass im out of our own control by returning it, we should decrement the retain count of im, to balance the increment and surrender ownership. But when can we possibly do that? If we do it before the line return im, the retain count of im will be zero and it will vanish in a puff of smoke; we will be returning a dangling pointer. But we can’t do itafter the line return im, because when that line is executed, our code comes to an end.

Clearly, we need a way to vend this object without decrementing its retain count now — so that it stays in existence long enough for the caller to receive and work with it — while ensuring that at some future time we will decrement its retain count, so as to balance our init(named:) call and fulfill our own management of this object’s memory. The solution is something midway between releasing the object and not releasing it — ARC autoreleases it.

Here’s how autoreleasing works. Your code runs in the presence of something called an autorelease pool. When ARC autoreleases an object, that object is placed in the autorelease pool, and a number is incremented saying how many times this object has been placed in this autorelease pool. From time to time, when nothing else is going on, the autorelease pool is automatically drained. This means that the autorelease pool releases each of its objects, the same number of times as that object was placed in this autorelease pool, and empties itself of all objects. If that causes an object’s retain count to be zero, so be it; the object is destroyed in the usual way. So autoreleasing an object is just like releasing it, but with a proviso, “later, not right this second.”

In general, autoreleasing and the autorelease pool are merely an implementation detail. You can’t see them; they are just part of how ARC works. So why am I telling you about them? It’s because sometimes, on very rare occasions, you might want to drain the autorelease pool yourself. Consider the following code (it’s slightly artificial, but that’s because demonstrating the need to drain the autorelease pool isn’t easy):

func test() {

let path = NSBundle.mainBundle().pathForResource("001", ofType: "png")!

for j in 0 ..< 50 {

for i in 0 ..< 100 {

let im = UIImage(contentsOfFile: path)

}

}

}

That method does something that looks utterly innocuous; it loads an image. But it loads it repeatedly. The variable to which the resulting string is assigned, im, is a local automatic variable, so you would expect that the image would come into existence and then go right back out of existence each time through the inner loop. Nevertheless, as the loop runs, memory climbs constantly (Figure 12-1); by the time our method comes to an end, our app’s memory usage has reached almost 32MB. This is not because the images aren’t being released each time through the loop; it’s because a lot of intermediate objects — things you’ve never even heard of, such as NSPathStore2 objects — are secondarily generated by our call to init(contentsOfFile:) and are autoreleased, and are all sitting there, piling up in the autorelease pool by the tens of thousands, waiting for the pool to be drained. When our code finally comes to an end, the autorelease pool is drained, and our memory usage drops precipitately back down to almost nothing.

Memory usage grows during a loop

Figure 12-1. Memory usage grows during a loop

Granted, 32MB isn’t exactly a massive amount of memory. But you may imagine that a more elaborate inner loop might generate more and larger autoreleased objects, and that our memory usage could potentially rise quite significantly. Thus, it would be nice to have a way to drain the autorelease pool manually now and then during the course of a loop with many iterations. Swift provides such a way — the global autoreleasepool function, which takes a single argument that you’ll supply as a trailing anonymous function. Before the anonymous function is called, a special temporary autorelease pool is created, and is used for all autoreleased objects thereafter. After the anonymous function exits, the temporary autorelease pool is drained and goes out of existence. Here’s the same method with an autoreleasepool call wrapping the inner loop:

func test() {

let path = NSBundle.mainBundle().pathForResource("001", ofType: "png")!

for j in 0 ..< 50 {

autoreleasepool {

for i in 0 ..< 100 {

let im = UIImage(contentsOfFile: path)

}

}

}

}

The difference in memory usage is dramatic: memory holds roughly steady at less than 2MB (Figure 12-2). Setting up and draining the temporary autorelease pool probably involves some overhead, so if possible you may want to divide your loop into an outer and an inner loop, as shown in the example, so that the autorelease pool is not set up and torn down on every iteration.

Memory usage holds steady with an autorelease pool

Figure 12-2. Memory usage holds steady with an autorelease pool

Memory Management of Instance Properties

Before ARC, managing memory for instance properties (Objective-C instance variables, Chapter 10) was one of the trickiest parts of Cocoa programming. The correct behavior is to retain a reference type object when you assign it to a property, and then release it when either of these things happens:

§ You assign a different value to the same property.

§ The instance whose instance property this is goes out of existence.

In order to obey the golden rule of memory management, the object taking charge of this memory management — the owner — clearly needs to be the object whose instance property this is. The only way to ensure that memory management of a property is handled correctly, therefore, is to implement it in the setter method for that property. The setter must release whatever object is currently the value of the property, and must retain whatever object is being assigned to that property. The exact details can be quite tricky (what if they are the same object?), and it was easy for programmers to get them wrong. And that, of course, is not the only memory management needed; to prevent a leak when the owner goes out of existence, the owner’s dealloc method (the Objective-C equivalent of deinit) had to be implemented to release every object being retained as the value of a property.

Fortunately, ARC understands all that, and the memory of instance properties, like the memory of all variables, is managed correctly for you.

This fact also gives us a clue as to how to release an object on demand. This is a valuable thing to be able to do, because an object may be using a lot of memory. You don’t want to put too great a strain on the device’s memory, so you want to release the object as soon as you’re done with it. Also, when your app goes into the background and is suspended, the Watchdog process will terminate it in the background if it is found to be using too much memory; so you might want to release this object when you are notified that the app is about to be backgrounded. (I talked about that problem in Chapter 3.)

You can’t (and mustn’t) call release explicity, so you need another way to do it, some way that is consonant with the design and behavior of ARC. The solution is to assign something else — something small — to this property. That causes the object that was previously the value of this property to be released. A commonly used approach is to type this property as an Optional — possibly, to simplify matters, an implicitly unwrapped Optional. This means that nil can be assigned to it, purely as a way of releasing the current value.

Retain Cycles and Weak References

As I explained in Chapter 5, you can get yourself into a retain cycle where two objects have references to one another — for example, each is the value of the other’s instance property. If such a situation is allowed to persist until no other objects have a reference to either of these objects, then neither can go out of existence, because each has a retain count greater than zero and neither will “go first” and release the other. Since these two objects, ex hypothesi, can no longer be referred to by any object except one another, this situation can now never be remedied — these objects are leaking.

The solution is to step in and modify how the memory is managed for one of these references. By default, a reference is a persisting reference (what ARC calls a strong or retain reference): assigning to it retains the assigned value. In Swift, you can declare a reference type variable as weakor as unowned to change the way its memory is managed:

weak

A weak reference takes advantage of a powerful ARC feature. When a reference is weak, ARC does not retain the object assigned to it. This seems dangerous, because it means that the object might go out of existence behind our backs, leaving us with a dangling pointer and leading to a potential crash later on. But ARC is very clever about this. It keeps track of all weak references and all objects assigned to them. When such an object’s retain count drops to zero and the object is about to be destroyed, ARC sneaks in and assigns nil to the reference — that’s why a weakreference in Swift must be an Optional, so that ARC can do that. Thus, provided you handle the Optional coherently, nothing bad can happen.

unowned

An unowned reference is a different kettle of fish. When you mark a reference as unowned, you’re telling ARC to take its hands off completely: it does no memory management at all when something is assigned to this reference. This really is dangerous — if the object referred to goes out of existence, you really can be left with a dangling pointer and you really can crash. That is why you must never use unowned unless you know that the object referred to will not go out of existence: unowned is safe, provided the object referred to will outlive the object that refers to it. That is why an unowned object should be some single object, assigned only once, without which the referrer cannot exist at all.

In real life, a weak reference is most commonly used to connect an object to its delegate (Chapter 11). A delegate is an independent entity; there is usually no reason why an object needs to claim ownership of its delegate, and indeed an object is usually its delegate’s servant, not its owner. Ownership, if there is any, often runs the other way; Object A might create and retain Object B, and make itself Object B’s delegate. That’s potentially a retain cycle. Therefore, most delegates should be declared as weak references:

class ColorPickerController : UIViewController {

weak var delegate: ColorPickerDelegate?

// ...

}

Unfortunately, large parts of Cocoa itself don’t use ARC. Cocoa’s memory management is carefully written, so that in general its retains and releases are balanced and it shouldn’t cause any memory leaks. Nevertheless, properties of built-in Cocoa classes that keep weak references are oftennon-ARC weak references (because they are old and backward-compatible, whereas ARC is new). Such properties are declared using the keyword assign. For example, UINavigationController’s delegate property is declared like this:

@property(nonatomic, assign) id<UINavigationControllerDelegate> delegate

In Swift, that declaration is translated like this:

unowned(unsafe) var delegate: UINavigationControllerDelegate?

The Swift term unowned and the Objective-C term assign are synonyms; they tell you that there’s no ARC memory management here. The unsafe designation is a further warning inserted by Swift; unlike your own code, where you wouldn’t use unowned unless it is safe, Cocoa’sunowned is potentially dangerous and you need to exercise caution.

Even though your code is using ARC, the fact that Cocoa’s code is not using ARC means that memory management mistakes can still occur. A reference such as a UINavigationController’s delegate can end up as a dangling pointer, pointing at garbage, if the object to which that reference was pointing has gone out of existence. If anyone (you or Cocoa) tries to send a message by way of such a reference, the app will then crash — and, since this typically happens long after the point where the real mistake occurred, figuring out the cause of the crash can be quite difficult. The typical sign of such a crash, in Swift, is that it takes place in _swift_abortRetainUnowned (Figure 12-3); note the reference to a “deallocated object.” (This is the sort of situation in which you might need to turn on zombies in order to debug, as I’ll describe later in this chapter.)

A crash from messaging a dangling pointer

Figure 12-3. A crash from messaging a dangling pointer

Defending against this kind of situation is up to you. If you assign some object to a non-ARC unsafe reference, such as a UINavigationController’s delegate, and if that object is about to go out of existence at a time when this reference still exists, you have a duty to assign nil (or some other object) to that reference, thus rendering it harmless.

Unusual Memory Management Situations

If you are using NSNotificationCenter to register for notifications (Chapter 11), and if you registered with the notification center using addObserver:selector:name:object:, you handed the notification center a reference to some object (usually self) as the first argument; the notification center’s reference to this object is a non-ARC unsafe reference, and there is a danger that after this object goes out of existence the notification center will try to send a notification to whatever is referred to, which will be garbage. That is why you must unregister before that can happen. This is similar to the situation with delegates that I was talking about a moment ago.

If you registered with the notification center using addObserverForName:object:queue:usingBlock:, memory management can be even more tricky, because:

§ The observer token returned from the call to add⁠Observer⁠For⁠Name:object:⁠queue:⁠usingBlock: is retained by the notification center until you unregister it.

§ The observer token may also be retaining you (self) through the block (a function, probably anonymous), if it refers to self. If so, then until you unregister the observer token from the notification center, the notification center is retaining you. This means that you will leak until you unregister. But you cannot unregister from the notification center in deinit, because deinit isn’t going to be called so long as you are registered.

§ In addition, if you also retain the observer token, then if the observer token is retaining you, you have a retain cycle on your hands.

Thus, use of addObserverForName:object:queue:usingBlock: can put you into the same situation that I described in Weak and Unowned References in Anonymous Functions. And the solution is the same: mark self as weak or (preferably) unowned in the anonymous function that you pass in as the block: argument.

Consider, for example, this (artificial) code, in which we, a view controller, register for a notification and assign the observer token to an instance property:

var observer : AnyObject!

override func viewWillAppear(animated: Bool) {

super.viewWillAppear(animated)

self.observer = NSNotificationCenter.defaultCenter().addObserverForName(

"woohoo", object:nil, queue:nil) {

_ in

self.description; return

}

}

Our intention is eventually to unregister the observer; that’s why we’re keeping a reference to it. It’s natural to do this in viewWillDisappear::

override func viewDidDisappear(animated: Bool) {

super.viewDidDisappear(animated)

NSNotificationCenter.defaultCenter().removeObserver(self.observer)

}

This works in the sense that the observer is unregistered; but the view controller itself is leaking. We can see this by logging on deinit:

deinit {

println("deinit")

}

In a situation where this view controller should be destroyed — for example, it was a presented view controller, and now it is being dismissed — deinit is never called. We have a retain cycle! The simplest solution is to mark self as unowned as it enters the anonymous function; this is safe because self will not outlive the anonymous function:

self.observer = NSNotificationCenter.defaultCenter().addObserverForName(

"woohoo", object:nil, queue:nil) {

[unowned self] _ in // fix the leak

self.description; return

}

Another unusual case is NSTimer (Chapter 10). The NSTimer class documentation says that “run loops maintain strong references to their timers”; it then says of scheduledTimerWithTimeInterval:target:... that “The timer maintains a strong reference to target until it (the timer) is invalidated.” This should set off alarm bells in your head: “Danger, Will Robinson, danger!” The documentation is warning you that as long as a repeating timer has not been invalidated, the target is being retained by the run loop; the only way to stop this is to send the invalidatemessage to the timer. (With a non-repeating timer, the problem doesn’t arise, because the timer invalidates itself immediately after firing.)

When you called scheduledTimerWithTimeInterval:target:..., you probably supplied self as the target: argument. This means that you (self) are being retained, and cannot go out of existence until you invalidate the timer. You can’t do this in your deinit implementation, because as long as the timer is repeating and has not been sent the invalidate message, deinit won’t be called. You therefore need to find another appropriate moment for sending invalidate to the timer. There’s no good way out of this situation; you simply have to find such a moment, and that’s that. For example, you could balance creation and invalidation of the timer by doing them in viewDidAppear: and viewWillDisappear::

var timer : NSTimer!

override func viewWillAppear(animated: Bool) {

super.viewWillAppear(animated)

self.timer = NSTimer.scheduledTimerWithTimeInterval(

1, target: self, selector: "dummy:", userInfo: nil, repeats: true)

self.timer.tolerance = 0.1

}

func dummy(t:NSTimer) {

println("timer fired")

}

override func viewDidDisappear(animated: Bool) {

super.viewDidDisappear(animated)

self.timer?.invalidate()

}

A more flexible solution is to use the block-based alternative to a repeating timer, available through GCD. You must still take precautions to prevent the timer’s block from retaining self and causing a retain cycle, just as with notification observers; but this is easy to do, and the result is that there is no retain cycle, so you can invalidate the timer in deinit if you want to. The timer “object” is a dispatch_source_t, and must be retained, typically as an instance property (which ARC will manage for you, even though it’s a pseudo-object). The timer will fire repeatedly after you initially “resume” it, and will stop firing when it is released, typically by setting the instance property to nil.

To generalize this approach, I’ve created a CancelableTimer class that can be used as an NSTimer replacement. It is basically a combination of a Swift closure and a GCD timer dispatch source. The initializer is init(once:handler:). The handler: is called when the timer fires. Ifonce: is false, this will be a repeating timer. It obeys two methods, startWithInterval: and cancel:

class CancelableTimer: NSObject {

private var q = dispatch_queue_create("timer",nil)

private var timer : dispatch_source_t!

private var firsttime = true

private var once : Bool

private var handler : () -> ()

init(once:Bool, handler:()->()) {

self.once = once

self.handler = handler

super.init()

}

func startWithInterval(interval:Double) {

self.firsttime = true

self.cancel()

self.timer = dispatch_source_create(

DISPATCH_SOURCE_TYPE_TIMER,

0, 0, self.q)

dispatch_source_set_timer(self.timer,

dispatch_walltime(nil, 0),

UInt64(interval * Double(NSEC_PER_SEC)),

UInt64(0.05 * Double(NSEC_PER_SEC)))

dispatch_source_set_event_handler(self.timer, {

if self.firsttime {

self.firsttime = false

return

}

self.handler()

if self.once {

self.cancel()

}

})

dispatch_resume(self.timer)

}

func cancel() {

if self.timer != nil {

dispatch_source_cancel(timer)

}

}

}

And here’s how to use it in a view controller; observe that we can cancel the timer in deinit, provided our handler: anonymous block avoids a retain cycle:

var timer : CancelableTimer!

override func viewDidLoad() {

super.viewDidLoad()

self.timer = CancelableTimer(once: false) {

[unowned self] in // avoid retain cycle

self.dummy()

}

self.timer.startWithInterval(1)

}

func dummy() {

println("timer fired")

}

deinit {

println("deinit")

self.timer?.cancel()

}

Other Cocoa objects with unusual memory management behavior will usually be called out clearly in the documentation. For example, the UIWebView documentation warns: “Before releasing an instance of UIWebView for which you have set a delegate, you must first set its delegateproperty to nil.” And a CAAnimation object retains its delegate; this is exceptional and can cause trouble if you’re not conscious of it.

Unfortunately, there are also situations where the documentation fails to warn of any special memory management considerations, but you can wind up with a retain cycle anyway. Discovering the problem can be tricky. Areas of Cocoa that have given me trouble include UIKit Dynamics (a UIDynamicBehavior’s action handler) and WebKit (a WKWebKit’s WKScriptMessageHandler).

Three Foundation collection classes — NSPointerArray, NSHashTable, and NSMapTable — are similar respectively to NSMutableArray, NSMutableSet, and NSMutableDictionary, except that (among other things) their memory management policy is up to you. An NSHashTable created with the class method weakObjectsHashTable, for example, maintains ARC-weak references to its elements, meaning that they are replaced by nil if the retain count of the object to which they were pointing has dropped to zero. You may find uses for these classes as a way of avoiding retain cycles.

Nib Loading and Memory Management

When a nib loads, it instantiates its nib objects (Chapter 7). What happens to these instantiated objects? A view retains its subviews, but what about the top-level objects, which are not subviews of any view? The answer is, in effect, that they do not have elevated retain counts; if someone doesn’t immediately retain them, they’ll simply vanish in a puff of smoke.

If you don’t want that to happen — and if you did, why would you be loading this nib in the first place? — you need to capture a reference to the top-level objects instantiated from the nib. There are two mechanisms for doing this. When a nib is loaded by calling NSBundle’sloadNibNamed:owner:options: or UINib’s instantiateWithOwner:options:, an NSArray is returned consisting of the top-level objects instantiated by the nib-loading mechanism. So it’s sufficient to retain this NSArray, or the objects in it.

In some cases, this happens without your even being aware of it. For example, when a view controller is automatically instantiated from a storyboard, it is actually loaded from a nib with just one top-level object — the view controller. So the view controller ends up as the sole element of the array returned from instantiateWithOwner:options:. The view controller is then extracted from this array and is retained by the runtime — by assigning it a place in the view controller hierarchy.

The other possibility is to configure the nib owner with outlets that will retain the nib’s top-level objects when they are instantiated. We did that in Chapter 7 when we set up an outlet like this:

class ViewController: UIViewController {

@IBOutlet var v : UIView! = nil

We then loaded the nib manually, with this view controller as owner:

NSBundle.mainBundle().loadNibNamed("View", owner: self, options: nil)

self.view.addSubview(self.v)

The first line instantiates the top-level view from the nib, and the nib-loading mechanism assigns it to self.v. Since self.v is a strong reference, it retains the view. Thus, the view is still there when we insert it into the interface in the second line.

The same thing happens when a view controller loads the nib containing its main view. The view controller has a view outlet, and is the owner of the nib. Thus, the view is instantiated and is assigned by the nib-loading mechanism to the view controller’s view property — which retains it.

It is common, however, for @IBOutlet properties that you declare to be marked weak. This is not obligatory, and it probably does no harm to omit the weak designation. The reason such outlets work properly even when they are designated weak is that you use this designation only when this is an outlet to an object that you know will be retained by someone else — for example, it’s a subview of your view controller’s main view. A view is retained by its superview, so unless you’re going to be removing this view from its superview later, you know that it will persist and there is no need for your @IBOutlet property to retain it as well.

Memory Management of CFTypeRefs

A CFTypeRef is a pure C analog to an Objective-C object. It is a pointer to an opaque C struct (see Appendix A), where “opaque” means that the struct has no accessible properties. This struct acts as a pseudo-object; a CFTypeRef is analogous to an object type. It is not an object type, however, and code that works with a CFTypeRef is not object-oriented; a CFTypeRef has no properties or methods, and you do not send any messages to it. You work with CFTypeRefs entirely through global functions, which are actually C functions.

In Objective-C, CFTypeRef types are distinguished by the suffix Ref at the end of their name. In Swift, however, this Ref suffix is dropped.

Here’s some Swift code for drawing a gradient:

let con = UIGraphicsGetCurrentContext()

let locs : [CGFloat] = [ 0.0, 0.5, 1.0 ]

let colors : [CGFloat] = [

0.3,0.3,0.3,0.8, // starting color, transparent gray

0.0,0.0,0.0,1.0, // intermediate color, black

0.3,0.3,0.3,0.8 // ending color, transparent gray

]

let sp = CGColorSpaceCreateDeviceGray()

let grad =

CGGradientCreateWithColorComponents (sp, colors, locs, 3)

CGContextDrawLinearGradient (

con, grad, CGPointMake(89,0), CGPointMake(111,0), 0)

In that code, con is a CGContextRef, known in Swift as a CGContext; sp is a CGColorSpaceRef, known in Swift as a CGColorSpace; and grad is a CGGradientRef, known in Swift as a CGGradient. They are all CFTypeRefs. The code is not object-oriented; it is a sequence of calls to global C functions.

Nevertheless, a CFTypeRef pseudo-object genuinely is a pseudo-object. This means that the thing pointed to — the C struct at the far end of the pointer — is effectively the same sort of thing that you’d find at the far end of a reference to a class instance. And that, in turn, means that memory for CFTypeRefs must be managed. In particular, a CFTypeRef pseudo-object has a retain count! And this retain count works exactly as for a true object, in accordance with the golden rule of memory management. A CFTypeRef must be retained when it comes within the sphere of influence of an owner who wants it to persist, and it must be released when that owner no longer needs it.

In Objective-C, the golden rule, as applied to CFTypeRefs, is that if you obtained a CFTypeRef object through a function whose name contains the word Create or Copy, its retain count has been incremented. In addition, if you are worried about the object persisting, you’ll retain it explicitly by calling the CFRetain function to increment its retain count. To balance your Create, Copy, or CFRetain call, you must eventually release the object. By default, you’ll do that by calling the CFRelease function; some CFTypeRefs, however, have their own dedicated object release functions — for example, for CGPath, there’s a dedicated CGPathRelease function.

In Swift, however, you will never need to call CFRetain, or any form of CFRelease; indeed, you cannot. Swift will do it for you, behind the scenes, automatically.

Think of CFTypeRefs as living in two worlds: the CFTypeRef world of pure C, and the memory-managed object-oriented world of Swift. When you obtain a CFTypeRef pseudo-object, it crosses the bridge from the CFTypeRef world into the Swift world. From that moment on, until you are done with it, it needs memory management. Swift is aware of this, and for the most part, Swift itself will use the golden rule and will apply correct memory management. Thus, for example, the code I showed earlier for drawing a gradient is in fact memory-management complete. In Objective-C, we would have to release sp and grad, because they arrived into our world through Create calls; if we failed to do this, they would leak. In Swift, however, there is no need, because Swift will do it for us.

Working with CFTypeRefs in Swift is thus much easier than in Objective-C. In Swift, you can treat CFTypeRef pseudo-objects as actual objects! For example, you can assign a CFTypeRef to a property in Swift, or pass it as an argument to a Swift function, and its memory will be managed correctly; in Objective-C, those are tricky things to do.

Once in a while, though, you will receive a CFTypeRef through some API that lacks memory management information. Such a value will come forcibly to your attention, because it will arrive into Swift as an Unmanaged generic wrapping the actual CFTypeRef. This is a form of warning that Swift does not know how to proceed with the memory management of this pseudo-object. You will in fact be unable to proceed until you unwrap the CFTypeRef by calling the Unmanaged object’s takeRetainedValue or takeUnretainedValue method. You will call whichever method tells Swift how to manage the memory for this object correctly. For a CFTypeRef obtained from a built-in function with Create or Copy in its name, call takeRetainedValue; otherwise, call takeUnretainedValue.

For example, this code comes from an app that uses the Address Book framework. This framework has a pure C API, which (as of this writing) has not been tweaked to provide Swift with memory management information:

let addr:ABMutableMultiValue = ABMultiValueCreateMutable(

ABPropertyType(kABStringPropertyType)).takeRetainedValue()

The call to ABMultiValueCreateMutable creates an ABMutableMultiValue, a CFTypeRef. But Swift doesn’t know how to manage its memory, so it arrives wrapped in an Unmanaged object. The call has Create in its name, so we send takeRetainedValue to the Unmanaged object to unwrap the actual ABMutableMultiValue.

Property Memory Management Policies

In Objective-C, a @property declaration (see Chapter 10) includes a statement of the memory management policy that is followed by the corresponding setter accessor method. It is useful to be aware of this and to know how such policy statements are translated into Swift.

For example, earlier I said that a UIViewController retains its view (its main view). How do I know this? Because the @property declaration tells me so:

@property(nonatomic,retain) UIView *view;

The term nonatomic tells you that the setter method, setView:, is not thread-safe. The term retain tells you that the setter retains the incoming UIView object. The Swift translation of this declaration doesn’t add any attribute to the variable:

var view: UIView!

The default in Swift is that a variable referring to a reference object type is a persisting reference — a strong reference. This means that it retains the object. Thus, you can safely conclude from this declaration that UIViewController retains its view.

The possible memory management policies for a Cocoa property are:

strong, retain (no Swift equivalent)

The default. The two terms are pure synonyms of one another; retain is the term inherited from pre-ARC days. Assignment to this property retains the incoming value and releases the existing value.

copy (no Swift equivalent, or @NSCopying)

The same as strong or retain, except that the setter copies the incoming value (by sending copy to it); the copy, which has an increased retain count already, becomes the new value.

weak (Swift weak)

An ARC-weak reference. The incoming object value is not retained, but if it goes out of existence behind our back, ARC will magically substitute nil as the value of this property, which must be typed as an Optional.

assign (Swift unowned(unsafe))

No memory management. This policy is inherited from pre-ARC days, and is inherently unsafe (hence the additional unsafe warning in the Swift translation of the name): if the object referred to goes out of existence, this reference will become a dangling pointer and can cause a crash if you subsequently try to use it.

You’d probably like to hear more about the copy policy, as I haven’t mentioned it until now. This policy is used by Cocoa particularly when an immutable class has a mutable subclass (such as NSString and NSMutableString, or NSArray and NSMutableArray; see Chapter 10). The idea is to deal with the danger of the setter’s caller passing in an object of the mutable subclass. A moment’s thought will reveal that this is possible, because, in accordance with the substitution principle of polymorphism (Chapter 4), wherever an instance of a class is expected, an instance of its subclass can be passed. But it would be bad if this were to happen, because now the caller might keep a reference to the incoming value and, since it is in fact mutable, could later mutate it behind our back. To prevent this, the setter calls copy on the incoming object; this creates a new instance, separate from the object provided — and belonging to the immutable class.

In Swift, this problem is unlikely to arise with strings and arrays, because on the Swift side these are value types (structs) and are effectively copied when assigned, passed as an argument, or received as a return value. Thus, Cocoa’s NSString and NSArray property declarations, when translated into Swift as String and Array property declarations, don’t show any special marking corresponding to Objective-C copy. But Cocoa types that are not automatically bridged from Swift structs do show a marking: @NSCopying. For example, the declaration of theattributedText property of a UILabel appears like this in Swift:

@NSCopying var attributedText: NSAttributedString!

NSAttributedString has a mutable subclass, NSMutableAttributedString. You’ve probably configured this attributed string as an NSMutableAttributedString, and now you’re assigning it as the UILabel’s attributedText. UILabel doesn’t want you keeping a reference to this mutable string and mutating it in place, since that would change the contents of the label without passing through the setter. Thus, it copies the incoming value to ensure that what it has is a separate immutable NSAttributedString.

You can do exactly the same thing in your own code, and you will want to do so. If your class has an NSAttributedString instance property, you’ll mark it as @NSCopying — and similarly for other members of immutable/mutable pairs, such as NSIndexSet, NSParagraphStyle, NSURLRequest, and so on. Merely providing the @NSCopying designation is sufficient; Swift will enforce the copy policy and will take care of the actual copying for you when code assigns to this property.

If, as is sometimes the case, your own class wants the internal ability to mutate the value of this property while preventing a mutable value from arriving from outside, put a private computed property façade in front of it that transforms it to the corresponding mutable type:

class StringDrawer {

@NSCopying var attributedString : NSAttributedString!

private var mutableAttributedString : NSMutableAttributedString! {

get {

if self.attributedString == nil {return nil}

return NSMutableAttributedString(

attributedString:self.attributedString)

}

set {

self.attributedString = newValue

}

}

}

@NSCopying can be used only for instance properties of classes, not of structs or enums — and only in the presence of Foundation, because that is where the NSCopying protocol is defined, which the type of a variable marked as @NSCopying must adopt.

Debugging Memory Management Mistakes

Though far less likely to occur under ARC (and Swift), memory management mistakes still can occur, especially because a programmer is prone to suppose (wrongly) that they can’t. Experience suggests that you should use every tool at your disposal to ferret out possible mistakes. Here are some of those tools (and see Chapter 9):

§ The memory gauge in the Debug navigator charts memory usage whenever your app runs, allowing you to observe possible memory leakage or other unwarranted heavy memory use. Note that memory management in the Simulator is not necessarily indicative of reality! Always observe the memory gauge with the app running on a device before making a judgment.

§ Instruments (Product → Profile) has excellent tools for noticing leaks and tracking memory management of individual objects.

§ Good old caveman debugging can help confirm that your objects are behaving as you want them to. Implement deinit with a println call. If it isn’t called, your object is not going out of existence. This technique can reveal problems that even Instruments will not directly expose.

§ Dangling pointers are particularly difficult to track down, but they can often be located by “turning on zombies.” This is easy in Instruments with the Zombies template. Alternatively, edit the Run action in your scheme, switch to the Diagnostics tab, and check Enable Zombie Objects. The result is that no object ever goes out of existence; instead, it is replaced by a “zombie” that will report to the console if a message is sent to it (“message sent to deallocated instance”). Be sure to turn zombies back off when you’ve finished tracking down your dangling pointers. Don’t use zombies with the Leaks instrument: zombies are leaks.

Even these tools may not help you with every possible memory management issue. For example, some objects, such as a UIView containing a large image, are themselves small (and thus may not cause the memory gauge or Instruments to register large memory use) but require a large backing store nevertheless; maintaining references to too many such objects can cause your app to be summarily killed by the system. This sort of issue is not easy to track down.