Saturday, June 27, 2009

From C++ to ObjC/Cocoa. Destination iPhone

I'm thinking about developing some applications for iPhone. I've never code anything for Mac, so starting this trip to IPhone, the first stop is ObjC/Cocoa. Here I have collected some information I found useful for  C++ programmer to start coding ObjC .

Concepts Translation

In ObjC compare to C++, the basic object oriented programming concepts are called  in a different way. I use this easy table to make the translation.

Member functionMethod
Data membersInstance variables
Multiple InheritanceNot available :D
Member function callObject message

Method declaration & Messages

ObjC syntax for methods is based on Smalltalk so there is nothing in common with C++. To show how to send a message to a instance let's suppose I already have an instance MyObject *objectInstance; declared.

Declaration / Message

The following table shows several examples of method declaration and method invocation = messaging

method: doSomething
arguments: 0
return value: 0
-(void) doSomething;[objectInstance doSomething];
method: getAnIntetger
arguments: 0
return value: 1(int)
-(int) getAnIntetger;int result = [objectInstance getAnInteger];
method: setAnInteger
arguments: 1(int)
return value: 0
-(void) setAnInteger:(int)value;[objectInstance setAnInteger:5];
method: setAnIntegerAndString
arguments:2 (int, string)
return value: 0
-(void) setAnIntegerAndString:(int)value withString:(NSString *)string;[objectInstance setAnIntegerAndString:5 withString:@"Jurl Jurl"];

If you replace - with + in the declaration, then the instance method becomes a class methods


When you use ObjC to write code based on the Foundation Framework, NSObject is the superclass that your classes should inherit from . The Foundation Framework, as its name highlights, is the main framework of the Cocoa Lib.  Corollary:  All your classes should inherit from NSObject.

Main methods implemented by NSObject

-(id) initDefault constructor
(NSString *) descriptionReturns a string with a brief description of the object
(BOOL) isEqual: (id)anObjectCompare object instances and returns YES if they are the same and NO otherwise

Simple Object/Class Declaration

I prefer learning from examples.  So from here I will start writing a simple object to show the fundamentals to code classes in ObjC.

FILE: MyObject.h
#import <Foundation/Foundation.h>

@interface MyObject : NSObject {
   // Declare instance variables
   // Basic types allocation is managed by the compiler
   int m_value;
   // Class instances are always managed through pointers
   // Allocation is a coder responsability
   NSString *m_string;

// Declare methods
- (int) getValue;
- (void) setValue: (int) value;
- (NSString *) getString;
- (void) setString: (NSString *) string;

Simple Object/Class Definition

FILE: MyObject.m
#import "MyObject.h"
@implementation MyObject
// Define methods
- (int) getValue
   // Compiler returns this value doing a copy
   return m_value;

- (void) setValue: (int) value
   // Compiler manages the copy of basic types variables
   m_value = value;

- (NSString *) getString
   // We just return a pointer, not a copy of the class instance
   return m_string;

- (void) setString: (NSString *) string
   if (string)
      // We tell the memory manager we have just finished using m_string instance
      [m_string release];

      // We point to the new string and tell the memory manager
      // that we are going to use the instance we have receive
      m_string = [string retain];


Intializers. Object instance creation

In ObjC, to create an instance of an object, you need explicitly 2 steps:
  1. Allocation
  2. Constructor/Initializer

Following code shows who create an object instance. Take a look at the ObjC message nesting syntax.
MyString *myString = [[MyString alloc] init];

Overwritting NSObject init method

To customize your object initialization is as easy as overwriting the init method of NSObject
FILE: MyObject.m (APPEND)

// id is the common type of any NSObject
- (id) init
 // First init the super class and check everything went OK
        if (![super init]) return nil;
        // Set initial value
 m_value = 75.0f;
        // Return instance, self = this
 return self;

Custom initializer with arguments

If you want your own customized initializer, you can do it of course. Let's see how to.

FILE: MyObject.h (APPEND)
- (id) initWithString: (NSString*)string;

FILE: MyObject.m (APPEND)
- (id) init
 return [self initWithString: [[NSString alloc] initWithFormat:@"defaultTitle"]];

- (id) initWithString: (NSString *)string
 if (![super init]) return nil;
 m_value = 75.0f;

 // Use retain to keep the
 m_string = [string retain];
 return self;

Understanding Memory Management

The memory management in ObjC is based on reference counting. All NSObjects have a retain counter.

  1. MyObject *myObject = [MyObject alloc];
    //returns an instance with retainCounter =
  2. [myObject retain];
    //make retainCounter++, call retain method if you want to keep the instance alive

  3. [myObject release];
    // make retainCounter--, call release method when you have finished using the instance

  4. When the retainCounter == 0, the dealloc method is called.

First thing required to avoid memory leaks is to implement dealloc method

FILE: MyObject.m (APPEND)
-(void) dealloc
   [m_string release];
   [super dealloc];


There is another way to avoid memory leaks without taking care of the retain counters. At least in iPhone applications you need to instance an allocation pool. And as far as I know, to do so, you create an NSAutoreleasePool instance during the initialization process. You can use the autorelease message to make the NSAutoreleasePool responsible for deallocating the object instances. Using this feature you do not control when the instance will be deallocated, it will depend on NSAutoreleasePool strategies.

This technique is NOT recommended for iPhone, because the memory resources of the phone aren't very large and it's a good idea deallocate instances as soon as they are not useful. But there are circumstances where there is no other option. If you want to overwrite NSObject method description, where you need to return an NSString, if you don't want to keep a description string as an instance variable you have to return an autorelease string because you can't release the return value before returning it.
- (NSString *) description
   NSString *result;
   result = [[NSString alloc] initWithFormat: @"Just an object to test];
   [result autorelease];
   // Alternative using class method
   // result = [NSString stringWithFormat:@"Just an object to test"];
   return result;


No comments:

Post a Comment