Objective-C Memory Management Essentials

By Gibson Tang , Maxim Vasilkov
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introduction to Objective-C Memory Management

About this book

Objective-C Memory Management Essentials will familiarize you with the basic principles of Objective-C memory management, to create robust and effective iOS applications. You will begin with a basic understanding of memory management, and why memory leaks occur in an application, moving on to autorelease pools and object creation/storage to get an idea of how memory is allocated. You will also see what ARC (Automatic Reference Counting) is and how it helps in memory management. Finally, you will cover examples on how to use the various tools provided by Xcode to help in memory management. You will also get a basic understanding of Swift, the recently introduced programming language to write interactive and lightning-fast applications.

By the end of this book, you will have all the necessary knowledge on how to effectively memory-manage your application with best practices.

Publication date:
March 2015
Publisher
Packt
Pages
200
ISBN
9781849697125

 

Chapter 1. Introduction to Objective-C Memory Management

In this chapter, we will concern ourselves principally with the core issues of the memory management problem as well as an Objective-C-based solution of it. We will look at the ownership and life cycle of the object. This basic idea is known as manual references counting, or Manual Retain Release (MRR), where you need to claim and relinquish ownership of every object. It defines an object's life cycle. And finally, we'll take a look deeper into NSObject for a better understanding of what's going on.

We will cover the following topics in this chapter:

  • Why do we need memory management in Objective-C?

  • An object's ownership and life cycle

  • The principles of reference counting

  • What's a memory leak and why pay attention to it?

 

Why do we need memory management in Objective-C?


It does not matter what programming language is being used; the question of memory management always persists. In general, it is a question of resource management that cannot be avoided because memory is always a limited resource.

The scripting languages and Java, where memory management is handled by the virtual machine or application (where it is hidden from the code), are not always effective enough. While it is easier for the programmer this way, it can have a negative impact on resources, since you don't have an absolute control of it and there are objects still "living" when we don't need them anymore, plus these "living" objects still occupy precious memory space, which can be used by other objects. Additionally, depending on what you ask, another opinion is that an automatic memory management is the only right way to go.

Such talks usually start discussions like "Which is the best programming language?" and" What is the best way of memory management?". Let's leave that meaningless business for blogs' and forums' "Holy-Wars". Every tool has it's use in the correct context and Objective-C memory management concept is quite efficient in terms of both time cost savings and resource saving.

The memory in Objective-C, is managed in a different way from some of the widespread languages such as C/C++, Java, or C#, which are typically taught in schools as it introduces new concepts such as object ownership. Memory management is crucial for devices that run on a limited amount of memory such as mobile phones, smart watches, and so on, since effective memory management will allow you to squeeze every ounce of performance needed to run efficiently on these small devices, where memory is scarce on these devices.

 

An object's ownership and life cycle


The idea of object ownership abstraction is simple—one entity is simply responsible for another and an entity has the ability to own an object. When an entity owns an object, the entity is responsible to free that object too.

Let's go to our code example. If an object was created and used in the main function, then the main function is responsible for the object, as the following code listing demonstrates:

int main(int argc, char *argv[]) {

  SomeObject *myOwnObject;
  // myOwnObject is created in main
   myOwnObject = [[SomeObject alloc] init];

    // myOwnObject can be used by other objects
  [anotherObject using:myOwnObject];
    
    // but main is responsible for releasing it
   [myOwnObject release];

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

What makes this concept a bit more complicated is that objects can be owned by more than one entity. So, an object may be created and owned in the main function and will also be used by another entity that will claim ownership of the object.

A common situation where you will see multiple object ownership is when you use arrays. Arrays are indexed lists of objects, and when an object is placed into an array, the array claims ownership of the object. So, if I create an object in the main function and then put that object into an array, both the main function and the array will claim ownership of the object and create a reference to it at the same time. Ownership and reference are different as an object references another object, which it does not own and both are responsible for cleaning up the object. The following code demonstrates this:

int main (int argc, char *argv[]) {

  SomeObject *myOwnObject;
  // myOwnObject is created in main
myOwnObject = [[SomeObject alloc] init];

// myOwnObject can be used by other objects
NSMutableArray *myArray;
// add my object to myArray    
myArray = [[NSMutableArray alloc] initWithObjects:myOwnObject, nil];
    
// main does not need myOwnObject any more
[myOwnObject release];

// but myOwnObject still is needed inside the array
[anotherObj usingArray: myArray];

Just like objects in the real world, Objective-C objects are created; they live, and then go away when the application is closed. This is how the object life cycle works. Obviously, arrays have to claim the ownership on the object and prevent it to be deleted in the release method called in the main function.

However, what is the correct way for the entity to claim its rights on an object that it owns? Let's take a deeper look at the problem.

 

Ownership of object and reference counting


To indicate the number of owners using objects, those objects are given a reference count.

At the beginning, the reference count of the object is 1. This happens because the function creating the object is going to use that object. When any entity needs to claim an ownership of the object, since that entity is going to access and use that object, it sends a retain message to it and its retain count is incremented by 1. When an entity is finished with the object, it sends the release message to the object and its retain count decrements by 1. As long as this object's reference count is higher than zero, some "things" are using it. When it comes to zero, the object is no longer useful for any of those "things", and it can be safely deallocated.

Let's return to the example with the object owned by an array. Explanations are given in the following code comments and diagram:

int main(int argc, char *argv[]) {

  SomeObject *myOwnObject;
  // myOwnObject is created in main
   myOwnObject = [[SomeObject alloc] init];
  // myOwnObject has retain count equal to 1

// myOwnObject can be used by other objects
NSMutableArray *myArray;
// add my object to myArray    
myArray = [[NSMutableArray alloc] initWithObjects:myOwnObject, nil];
//inside myOwnObject got another retain message
//and now its retain count equal 2
    
// main does not need myOwnObject any more
[myOwnObject release];
// release decrements retain count
// and now myOwnObject retain count now is 2-1 = 1

// but myOwnObject still is needed inside the array
[anotherObj usingArray: myArray];

[myArray release];
// on array destruction every object inside array gets release message

//myOwnObject retain count decreases this time to 0 and myOwnObject will be deleted together with the array

The following diagram illustrates the principle of reference counting:

Forgetting to send a release message to an object before setting a pointer to point at something else will guarantee you a memory leak. In order to create an object before it's initiated, a chunk of the OS memory is allocated to store it. Also, if you send a release statement to an object, which was not previously sent, a retain statement is sent to the object. This will be considered as a premature deallocation, where the memory previously allocated to it is not related to it anymore. A lot of time is spent on debugging these issues, which can easily become very complex in large projects. If you don't follow some solid principles for memory management, you can often forget and quickly find yourself getting stuck for hours checking every retain and release statement. Even worse is if you're going through someone else's code, and they mess things up. Going through to fix memory management issues in someone else's code can take forever.

 

What's a memory leak and why pay attention to it?


A memory leak is when your program loses track of a piece of memory that was allocated and has forgotten to release it. The consequence is that the "leaked" memory will never be freed by the program. When more memory is leaked after a certain point in time, there will be no more free memory and this will cause your application to crash. Usually, this tends to happen when a piece of code does new, malloc, or alloc, but never does a corresponding "delete", "free", or "release" respectively.

When you do new, malloc, or alloc, what the operating system does is that it is giving your program a chunk of memory on the heap. The OS says, "Here, take this memory address and have this block of memory on it." Thus, you need to create a reference to that memory address (usually in the form of a pointer), depending on the OS, such as, "I'm done with this, it's not useful anymore" (by calling "free", "delete", or "release").

Memory leaks happen when you throw away your pointer to that memory. If your program does not retain where your memory is allocated on the heap, how can you even free it? The following line of code shows an example of a memory leak if you never call the release method on it:

NSMutableString *str = [[NSMutableString alloc] initWithString:@"Leaky"];

So why should you care? At best, you're the dissipating memory that will be freed when the user quits your app. At worst, there could be a memory leak that happens in every screen. It would not be a great mode to end up your program, especially if the user lets it run for a long time. A program crash is very hard to debug as it can crash at random moments in your application as memory leaks are very unpredictable to replicate and creating an application that crashes often will lead to bad reviews of your program on the App Store, or through word of mouth, which is something that you do not want to happen.

This is why in the process of evolution, there are other methods of memory management in Objective-C, which you will find further in this book.

 

What is an object within Objective-C?


How do things work inside Objective-C? NSObject is the root class of most Objective-C class hierarchies, through it an object inherits basic methods and behaves like an Objective-C object.

This object is an instance of a class and can also be a member of a class or one of its derivatives. So, let's take a deeper look at NSObject. In the early stage, Objective-C had a class called Object. This had a method called +new, which wrapped malloc(), and a method called -free. Since Objective-C objects were generally aliased and managing object life cycles became quite complex, this was troublesome.

NSObject is used by NeXT—Steve Job's second company, founded after he was fired from Apple in 1985—in order to provide reference counting, thus, dividing Object pointers in two categories: pointers that own references and pointers that do not own references. Those pointers that contribute towards the object's reference count are owning reference pointers. If there is a certainty that a reference is going to be held somewhere else for the duration of a variable's lifetime, a non-owning reference pointer can be used avoiding the additional overhead of reference count manipulation since a non-owning reference pointer does not have the added cost of keeping track of object ownership.

Non-owning reference pointers are often used for autoreleased values. Autorelease pools make it possible for a temporary object to receive a non-owning reference pointer in return. An object, by receiving an -autorelease message is added to a list that will be deallocated afterwards, with the destruction of the current autorelease pool. You can call autorelease using the autorelease method as shown here:

 [myObject autorelease];

The following table shows some description on the roles of autorelease and release:

Release type

Description

The autorelease method

An object is sent a release message, but put in an autorelease pool and the object is released when the pool is drained later during the run loop, but still occupies memory

The release method

An object is released immediately and memory is freed after the object is released

Any object that receives the autorelease message will be released when the autorelease pool is drained. Using autorelease instead of the normal release method will extend the lifetime of an object until the pool is drained at the end of the run loop.

At Worldwide Developers Conference (WWDC) 2011, Apple introduced ARC, the acronym of Automatic Reference Counting. It forces the compiler to handle the memory management calls at compile time instead of the conventional garbage collection functionality, which occurs during runtime. ARC also adds some things to the language model in general. It has been supported since iOS5, OS X 10.7, and by GNUstep.

First, what we will find out is that there are two NSObjects in Cocoa, a class and a protocol. Why is this so and what is the purpose of this? Let's look into classes and protocols.

In Objective-C, protocols define a set of behaviors that an object is expected to conform to in certain situations at runtime. For example, a table view object is expected to be able to communicate with a certain data source so that the table view will know what data and information to display. Protocols and classes do not share the same namespaces (a set of identifiers containing names, the names of classes and protocols, thus the same name can exist in different namespaces). It's possible to have both, which are unrelated at the language level, but have the same name. This is the case with NSObject.

If you look at the language, there are no places where you can use either a protocol or a class name. Using class names as the target of message sends, as type names, and in @interface declarations is allowed. Likewise, it's possible to use protocols names in a few identical places; however, not in the same way. Having a protocol with the same name as a class won't result any issue.

It is impossible for root class to have a superclass as they are at the top of the hierarchy, so there is no superclass above a root class and NSObject class is one of them. And I give emphasis on saying one of them because in comparison to other programming languages in Objective-C, it's perfectly possible to have the existence of multiple root classes.

Java's single root class is named java.lang.Object, which is the parent ultimate class of any other. For this reason, any piece of code in Java, which comes from any object, has the basic methods added by java.lang.Object.

Cocoa can have multiple root classes. Besides NSObject, there is NSProxy and a few others root classes; and such root classes are, in part, the reason for the existence of the NSObject protocol. The NSObject protocol determines a specific set of basic methods, expecting their implementation by the others root classes, consequently, making those methods available whenever and wherever they are needed.

The NSObject class is in accordance to the NSObject protocol, which results in the implementation of this basic method:

   //for NSObject class 
  @interface NSObject <NSObject>

Implementing the same method works for NSProxy, which is also in accordance to the NSObject protocol:

   // for NSProxy class @interface NSProxy <NSObject>

Methods such as hash, description, isEqual, isKindOfClass, isProxy, and others are found in the NSObject protocol. NSProxy to NSObject protocol denotes that, implementing the basic NSObject methods, it's still possible to count on NSProxy instances.

Subclassing NSObject would pull in a lot of baggage that may cause a problem. NSProxy assists in order to prevent this by giving you a simpler superclass that doesn't have so much extra stuff in it.

The fact that the NSObject protocol is useful for root classes isn't all that interesting for most Objective-C programming, for the simple fact that we don't make use of other root classes frequently. However, it will be very convenient when you need to make your own protocols.

Let's say, you have the following protocol:

    @protocol MyOwnProtocol
    - (void)myFunction;
    @end

And there is a pointer to a simple object, myOwnObject, that accords to it:

    id<MyProtocol> myOwnObject;

You can tell this object to perform myFunction:

    [myOwnObject myFunction];

However, you cannot ask the object for its description:

    [myOwnObject description]; // no such method in the protocol

And you can't check it for equality:

    [myOwnObject isEqual: anotherObject];
    // no such method in the protocol

In general, you can't ask it to do any of the stuff that a normal object can do. There are times when this doesn't have any importance, but in some circumstances, you will wish to be able to perform this task.

As mentioned earlier, NSObject, the root class of most Objective-C class hierarchies and through NSObjects, your Objective-C classes can inherit an interface to the system and also gain the ability to behave as Objective-C objects. So, NSObject is important if you want your objects to gain access to methods such as isEqual, so on, and so forth. This is where the NSObject protocol comes into the picture. Protocols can inherit from other protocols, which means that MyProtocol can inherit from the NSObject protocol:

    @protocol MyOwnProtocol <NSObject>
    - (void)myFunction;
    @end

This says that not only do objects that conform to MyOwnProtocol respond to myFunction, but they also respond to all those common messages in the NSObject protocol. Knowing that any object in your application directly or indirectly inherits from the NSObject class, that it's in accordance to the NSObject protocol, there is no imposition to any additional requirements on people implementing MyOwnProtocol, while giving you the permission to use these basic methods on instances.

Note

The fact that there are two different NSObjects is abnormal for the frameworks; however, it starts to make sense when you go deeper into it. The NSObject protocol grants the permission to all root classes that have the same basic methods, making, also, a very easy way to declare a protocol that also includes basic functionality expected from any object. The NSObject class introduces it all together, since it's in accordance to the NSObject protocol. One thing to note here is that a custom class that's created and does not inherit NSObject can be considered as a root class, but once you make your custom class inherit from NSObject, then the root class won't be your custom class anymore, and the root class will be NSObject. However, generally, most of your custom classes should inherit from NSObjects; it will implement NSObject's functionality such as alloc, init, release, and so on and without inheriting from NSObject, these functionalities need to be written and implemented by you.

 

Summary


In this chapter, you learned what memory management in Objective-C is and how it works. You also learned the best practices while working with Manual Retain Release, and got an introduction to Automatic Reference Counting, Objective-C Objects, and root classes. ARC basically can be considered as a compile time guard against memory leaks as the compiler will automatically write the release statements for you at compile time. So, there is no need to write verbose release statements in your code to keep it clean and terse.

One tip to note for coding with memory management is that whenever you do alloc and init, then write your release code after that and put it in its appropriate place in your class, you can forget to call the release method after writing some or fixing some bugs. So writing your object release statements after you do alloc and init will help you to keep memory leaks to a minimum so that you won't have a situation where you get a memory leak as you have forgotten to write your object release statement.

In the next chapter, you will learn more about ARC, how it works, its advantages, how to set up your projects to use ARC and memory models in Objective-C and UI Kit with ARC.

About the Authors

  • Gibson Tang

    Gibson Tang grew up loving technology after getting his hands on an old Apple II when he was still a young kid. Since then, he has never stopped keeping pace with technology, and after he coded his first "Hello World" program, he has been hooked on programming ever since.

    Following his studies at Nanyang Polytechnic and Singapore Institute of Management and serving a 6-year stint in the Republic of Singapore Navy (RSN), he honed his development skills creating software and games for Yahoo! and other Fortune 500 companies. In 2010, he founded Azukisoft Pte Ltd in Singapore to focus on mobile application development. Since then, he has developed countless mobile applications and games for start-ups and big companies both in USA and Singapore.

    Apart from programming, he indulges in various hobbies such as soccer, computer games, and jogging in order to get his regular dose of Vitamin D and to see the sun once in a while. Occasionally, he would be on Steam or Battle.net blowing off some steam by slaying monsters and killer robots after a day of programming.

    Browse publications by this author
  • Maxim Vasilkov

    Maxim Vasilkov is a mobile software developer in Azukisoft Pte Ltd. He started programming over 10 years ago. He started with iOS when the SDK was made publicly available, and from that time onwards, he developed a passion for making mobile apps. He is also experienced with other programming languages and has expertise working with various team sizes, which gave him the opportunity to look at different approaches to programming. Outside of work, he is a proud father of beautiful triplets, Anna, Maria, and Victoria, who are now 4 years old. This has helped him try out mobile games for kids and enables him to be an expert in mobile games for kids.

    Browse publications by this author
Book Title
Access this book, plus 7,500 other titles for FREE
Access now