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.

C++ObjC
ClassObject
Member functionMethod
Data membersInstance variables
ConstructorInitializer
DestructorDeallocator
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
declarationmessaging
-(void) doSomething;[objectInstance doSomething];
method: getAnIntetger
arguments: 0
return value: 1(int)
declarationmessaging
-(int) getAnIntetger;int result = [objectInstance getAnInteger];
method: setAnInteger
arguments: 1(int)
return value: 0
declarationmessaging
-(void) setAnInteger:(int)value;[objectInstance setAnInteger:5];
method: setAnIntegerAndString
arguments:2 (int, string)
return value: 0
declarationmessaging
-(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

NSObject


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;
 @end

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];
   }
}

@end

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];
}

AutoRelease


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;
}

References

No comments:

Post a Comment