Saturday, May 21, 2011

Objective-C Memory Management.

 

I started learning Objective-C because I wanted to program iPhone/iPad applications. I heard that the language had garbage collection, but I was disappointed when I read it only worked for Mac OS X. Coming from a .Net background, memory management seemed like advanced black magic to me. As it turns out though, it’s really not that complicated –if you follow certain rules.

 

Memory management in Objective-C is based on “object ownership”. An object can have one or more “owners”. The number of ”owners” is stored in each object using a mechanism called reference counting. You can think of this number as a counter of the number of “owners” an object has. Reference counting in Objective-C works like this:

 

·     When you “create” an object its reference count is 1.

·     When you “take ownership” of an object, you increase its reference count by 1.

·      When you “release” an object, you decrease its reference count by 1.

·      When you “autorelease” an object, you flag it to be released later by an auto release pool. When the object is released, its reference count it’s decreased by 1.

·      When an object reference count is 0, the object is “deallocated” or destroyed. The objects “dealloc” method gets called automatically, and its memory footprint is 0.

·      Once an object is “deallocated”, it cannot be used anymore.

 

So, how can you “create” or “claim ownership” of an object?

 

·      You can create or “own an object”, by using a method whose name begins with “alloc” or “new”.

·      You can “claim ownership” of an object when you call “retain”, or call a method that starts with “copy” or “mutableCopy”.

 

To clarify how you can “create” an object, I’ll be using the class I defined in my previous post.

 

Camera * myFirstCamera = [[Camera alloc] init];

 

I’m calling “alloc” therefore I “own” the object. Also, the myFirstCamera object reference count is 1.

 

I can now use the object…

 

[myFirstCamera focus];

[myFirstCamera takePicture];

 

When I’m done using the camera instance, I relinquish the object by calling release.

 

[myFirstCamera release];

 

The camera object reference count decreases by one, becomes equal to 0, and the camera object is destroyed.

 

If you want to use an object in a different scope from which it’s declared, you need to prevent it from being destroyed. You do this by “taking ownership” of the object. Storing an object inside a class is one example of when you would want to do this. To explain this, in the Camera.h interface file, I’m going add a manufacturer member variable.

 

NSString *manufacturer;

 

Next, I’m going to add accessor methods.

 

-(void) setManufacturer:(NSString *)manufacturerArg;

-(NSString*) manufacturer;

 

The syntax “:(NSString *) manufacturerArg” for sending an argument to a function is strange at first glance, but you'll get used to it the more you code.

 

 

Now to “claim ownership” of an object, we use a setter method.

 

 

-(void) setManufacturer:(NSString *)manufacturerArg{

    if(manufacturerArg  != manufacturer){

       [manufacturer release];

       manufacturer = [manufacturerArg copy];

    }

}

 

The manufacturerArg is an object which we don’t own. Because we don’t own it, it might get deallocated at some point. This is one example, when you would want to “claim ownership” of an object. To accomplish this purpose, you can call “retain” or “copy”. Calling “retain” will copy the reference of the string object, and copy will return a new object that has the same content as the argument. Both “retain” and “copy” increase the reference count by one. Although when using strings, it’s preferable to use “copy”, because we don’t want external changes to affect the state of our variable. Before I call copy, I release the previous reference stored by calling “release”. 

 

 

 

The implementation of the getter method in the Camera.m file is:

 

 

-(NSString*) manufacturer{

    return [[manufacturer copy] autorelease];

}

 

I return a copy of the member variable, so external changes won’t affect the manufacturer member variable in my class. When I called copy, I increased the reference count by one. For this reason, I must balance the reference count by calling “autorelease”. In addition to this, when you call “autorelease”, the object is added to the current topmost autorelease pool. When the objects go out of context the autorelease pool calls the drain method, which decreases the reference count of all the objects by one. When developing iOS applications Xcode creates autorelease pools, for every event dispatch, you as a programmer don’t need to worry about it. You just need to know that one of the autorelease pools, will decrement the reference count of your object by one, at some point in the future. Of course, this auto release pools can also be created manually.

 

A corollary from the previous code is an important memory management rule.

 

You only call “release” or “autorelease” on objects you own.

 

Now since I added the manufacturer member variable, there is a reference to an NSString object now. In the setter methods, I’m retaining the object to prolong its life. However, the camera class as it stands now would leak memory. Why? Because, I’m not releasing the manufacturer object. Once the camera object is destroyed, there would be no way to reference the manufacturer variable. As a result, I’m creating a memory leak.  To fix this, I need to call the release method inside the destructor.

 

-(void) dealloc{//destructor of the camera object.

    [manufacturer release]; //fix the leak.

    [super dealloc]; //the only time you should ever call the "dealloc" method.

}

 

By calling “release”, I balance the reference count in the camera object, and fix the leak. The [super dealloc] calls the NSObject dealloc function to release it’s memory. The super keyword refers to the base class(NSObject) of the camera object. This is the only context from which the “dealloc” should ever be called. In a way, this leads us to another very important memory management rule:

 

 

You should never call another objects dealloc method directly.

 

Okay, so now that we know about memory management let’s use our method.

 

NSString *manufacturer = @"Canon";

NSString *autoreleasedManufacturer = [NSString stringWithFormat:@"%@", manufacturer];

 

[myFirstCamera setManufacturer:autoreleasedManufacturer];

  

  

The stringWithFormat is a constructor method that returns an “autoreleased” string. The method doesn’t start with “alloc”, “new”, “copy” or “mutableCopy”, as a result you don’t own the autoreleasedManufacturer object, and you shouldn’t call release. If you implement your own methods, you should also follow the same convention.

 

Now let’s look at a situation when you would release a string.

 

 

NSString *mustReleaseManufacturer = [[NSString alloc] initWithFormat:@"%@", manufacturer];

[myFirstCamera setManufacturer: mustReleaseManufacturer];

[mustReleaseManufacturer release];

 

The mustReleaseManufacturer string is created using alloc, so I must release the object after using it.

 

 

To conclude, let’s mention the most important rules:

 

·       You should only release or autorelease objects you own.

·       You must override dealloc method to release the objects you own.

·       Never call another objects dealloc method directly.

 

Friday, May 13, 2011

Creating a custom object in Objective-C

 

I started learning Objective-C and Cocoa about a month ago. I’m going to be posting here how I see the language from my perspective as a C# .Net developer….. so lets start!

 

The first thing that I want to know when learning a new language, is how to create my own custom object. In order to create a class you should derive from NSObject. This object has all the smarts for memory management and other basic functionality.

 

The second thing is to know is what type of object to create. I like taking pictures, so I’m going to create my own camera object. An Objective-C class is typically separated into two files.

 

 

The first file Camera.h contains the interface for the class.

 

 

@interface Camera : NSObject {

    //instance variables

    double aperture;

    double shutterSpeed;

  

}

 

//method declarations.

-(id) init;

-(void) focus;

-(void) takePicture;

 

@end

 

Okaaaay what’s up with those minus signs? Turns out that the minus signs represent instance methods. In contrast,  the + sign is used for static methods.  Notice I need to derive from NSObject explicitly. If I didn’t, my camera class would need to reinvent the wheel, and I’m sure I don’t want to do that. The method naming convention is also different from C#, the convention is: method names and variable names start with a lower case letter. Class naming seem familiar however, class names start with an uppercase letter.

 

The second file, Camera.m contains the implementation.

  

#import "Camera.h"

 

@implementation Camera

 

//method implementations

 

-(id) init{

    self = [super init];

    if(self){//always use this pattern in a constructor.

         aperture =2.8;

         shutterSpeed = 1/60;

    }

   return self;

}

 

-(void) focus{

//focus mechanism

}

-(void) takePicture{

//take picture functionality

}

@end

 

No need to mention NSObject again, I just need to implement the methods I declared in the interface.I also need to import the Camera.h file. Notice init returns an id type. The id type can hold a reference to any object, kind of like the System.Object in .Net.  Now somewhat less intuitive, but very important,  is the need to add the following initializer pattern inside the constructor.

 

    self = [super init];

    if(self){

       //Implementation of constructor.

    }

   return self;

 

The keyword super is used to call the base class constructor. What would happen if init returns nil ? In Objective-C sending message to nil has no effect at runtime! How cool is that? Using a null object in .Net is a common source of bugs.

 

I can now create my own camera like this:

 

Camera *myFirstCamera = [Camera alloc];

[myFirstCamera init];

 

The [ ] notation will probably hurt your eyes, but it’s how you call methods in Objective-C. The Camera class calls the static method alloc to allocate memory for the object. Then, the init ‘constructor’ method is called to initialize the member variables of the camera object.

 

Usually you group both calls in one line like this:

 

Camera * myFirstCamera = [[Camera alloc] init]; //buy the camera

 

Now we can use our camera…

 

[myFirstCamera focus];

[myFirstCamera takePicture];

//..

[myFirstCamera release];//clean up...