Read iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) Online
Authors: Aaron Hillegass,Joe Conway
Tags: #COM051370, #Big Nerd Ranch Guides, #iPhone / iPad Programming
In simple applications like
RandomPossessions
, we only use a handful of classes. However, as applications grow larger and more complex, the number of classes grows. At some point, you will run into a situation where you have two classes that could easily be named the same thing. This is bad news. If two classes have the same name, it is impossible for your program to figure out which one it should use. This is known as a
namespace collision
.
Other languages solve this problem by declaring classes inside a
namespace
. You can think of a namespace as a group, to which classes belong. To use a class in these languages, you have to specify both the class name and the namespace.
Objective-C has no notion of namespaces. Instead, we prefix class names with two or three letters to keep them distinct. For example, in this exercise, the class was named
BNRItem
instead of
Item
.
Stylish Objective-C programmers always prefix their model and view classes. The prefix is typically related to the name of the application you are developing or the library it belongs to. For example, if I were writing an application named
“
MovieViewer,
”
I would prefix all classes with
MV
. Classes that you will use across multiple projects typically bear a prefix that is related to your name (
JC
), your company’s name (
BNR
), or a portable library (a library for dealing with maps might use
MAP
).
Controller objects, on the other hand, are typically only used in a single application and do not need a prefix. This isn’t a rule – you can prefix your controller objects if you like, and you definitely should if they will be used in other applications.
Notice that Apple’s classes have prefixes, too. Apple’s classes are organized into frameworks (which we’ll talk about in
Chapter 4
), and each framework has its own prefix. For instance, the
UILabel
class belongs to the UIKit framework. The classes
NSArray
and
NSString
belong to the Foundation framework. (The
NS
stands for NeXTSTEP, the platform for which these classes were originally designed.)
In this chapter, you’ll learn how memory is managed in iOS and the concepts that underlie
automatic reference counting
, or ARC. We’ll start with some basics of application memory.
All Objective-C objects are stored in a part of memory called
the heap
. When we send an
alloc
message to a class, a chunk of memory is allocated from the heap. This chunk includes space for the object’s instance variables.
For example, consider an instance of
NSDate
, which represents a specific point in time. An
NSDate
has two instance variables: a
double
that stores the number of seconds since a fixed reference point in time and the
isa
pointer, which every object inherits from
NSObject
. A
double
is eight bytes, and a pointer is 4 bytes, so each time
alloc
is sent to the
NSDate
class, 12 bytes is allocated from the heap for a new
NSDate
object.
Consider another example:
BNRItem
. A
BNRItem
has five instance variables: four pointers (
isa
,
itemName
,
serialNumber
, and
dateCreated
) and an
int
(
valueInDollars
). The amount of memory needed for an
int
is four bytes, so the total size of a
BNRItem
is 20 bytes (
Figure 3.1
).
Figure 3.1 Byte count of BNRItem and NSDate instances
Notice in
Figure 3.1
that the
NSDate
object does not live inside the
BNRItem
. Objects never live inside one another; they exist separately on the heap. Instead, objects keep references to other objects as needed. These references are the pointer instance variables of an object. Thus, when a
BNRItem
’s
dateCreated
instance variable is set, the
address
of the
NSDate
instance is stored in the
BNRItem
, not the
NSDate
itself. So, if the
NSDate
was 10, 20, or even 1000 bytes, it wouldn’t affect the size of the
BNRItem
.)
There is another part of memory called the
stack
that is separate from the heap. The reason for the names heap and stack has to do with how we visualize them. The heap is a giant heaping mess of objects, and we use pointers to remember where those objects are stored within the heap. The stack, on the other hand, can be visualized as a physical stack of
frames
.
When a method (or function) is executed, it allocates a chunk of memory from the stack. This chunk of memory is called a frame, and it stores the values for variables declared inside the method. A variable declared inside a method is called a
local variable
.
When an application launches and runs the
main
function, the frame for
main
is put at the bottom of the stack. When
main
calls another method (or function), the frame for that method is added to the top of the stack. Of course, that method could call another method, and so on, until we have a towering stack of frames. Then, as each method or function finishes, its frame is
“
popped off
”
the stack and destroyed. If the method is called again, a brand new frame will be allocated and put on the stack.
For example, in your
RandomPossessions
application, the
main
function runs
BNRItem
’s
randomItem
method, which in turn runs
BNRItem
’s
alloc
method. The stack would look like
Figure 3.2
. Notice that
main
’s frame stays alive while the other methods are executing because it has not yet finished executing.
Figure 3.2 Stack growing and shrinking
Recall that the
randomItem
method runs inside of a loop in the
main
function. So with every iteration, the stack grows and shrinks as frames are pushed on and popped off the stack.
Pointer variables convey
ownership
of the objects that they point to.
Think back to your
RandomPossessions
application as a whole. Or, better yet, reopen
RandomPossessions.xcodeproj
and have another look at the code in
main.m
. In this application, an instance of
NSMutableArray
is created in the
main
function, and then 10
BNRItem
instances are added to the array.
Figure 3.3
shows the objects in
RandomPossessions
and the pointers that reference them.
Figure 3.3 Objects and pointers in RandomPossessions
The
NSMutableArray
is pointed to by the local variable
items
within the
main
function, so the
main
function owns the
NSMutableArray
. Each
BNRItem
instance owns the objects pointed to by its instance variables.
In addition, the
NSMutableArray
owns the
BNRItem
s. Recall that a collection object, like an
NSMutableArray
, holds pointers to objects instead of actually containing them. These pointers convey ownership: an array owns the objects it points to.
The relationship between pointers and object ownership is important for understanding memory management in iOS.