Objective-C Beginner's Guide
Objective-C Beginner's Guide
Outline
Getting Started
Downloading this tutorial
Setting up the environment
Preamble
Making hello world
Creating Classes
@interface
@implementation
Piecing it together
The Details...
Multiple Parameters
Constructors
Access Privledges
Class level access
Exceptions
Inheritance, Polymorphism, and other OOP features
The id type
Inheritance
Dynamic types
Categories
Posing
Protocols
Memory Management
Retain and Release
Dealloc
Autorelease Pool
Foundation Framework Classes
NSArray
NSDictionary
Pros and Cons
More Information
Getting Started
Downloading this tutorial
All the source code for this beginners guide including makefiles is available by
downloading objc.tar.gz. Many of the examples in this tutorial were written by Steve
Kochan in the book Programming in Objective-C. If you want more detailed
information and examples, feel free to check out his book. The examples on this site
were used with his permission, so please don't copy them.
http://www.otierney.net/objective-c.html Page 1 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
system. Some put it in /usr, some /usr/lib, some /usr/local. If your shell is a
csh/tcsh based shell, you'll want to execute GNUStep.csh instead. It's
recommended that you put this script in your .bashrc or .cshrc.
Mac OS X: Install XCode
Windows NT 5.X: Install cygwin or mingw and then install GNUStep
Preamble
This tutorial assumes you have some basic C knowledge, including C data types, what
a function is, what a return value is, knowledge of pointers and basic memory
management in C. If you haven't gotten this far, I highly suggest you pick up K and
R's book, The C Programming Language . This is the book on C written by the writers
of C.
Objective-C, being a C derivative, inherits all of C's features. There are a few
exceptions but they don't really deviate from what C offers as a language.
nil: In C/C++ you're probably used to NULL. In Objective-C it is nil. The difference is
you can pass messages to nil (such as [nil message];) and this is perfectly legal. You
cannot however do this with NULL.
BOOL: C doesn't have an official boolean type, and in reality neither does Objective-
C. It's however built into the Foundation classes (Namely from importing
NSObject.h). nil is also included in this header file. BOOL in Objective-C has two
modes, YES and NO rather than TRUE and FALSE.
#import vs #include: As you will notice in the hello world example, #import was used.
#import is supported by the gcc compiler, however it is deprecated in favor of
#include. #import is basically the same thing as #ifndef #define #endif at the top and
bottom of every .h file you make. I find this to be retarded, as many other
programmers will most likely agree. For all purposes, just use #import. It's less hassle,
and if gcc ever does remove it chances are enough Objective-C developers exist to
either keep it from getting removed or getting added back in. As an aside, Apple
officially uses #import in all their code so if this ever did happen, you can be certain
that Apple would conviently ship a forked version of gcc to add this back in.
The word method and message are used interchangably in Objective-C, although
messages have special properties. A message can be dynamically forwarded to another
object. Calling a message on an object in Objective-C doesn't mean that the object
implements that message, just that it knows how to respond to it somehow via directly
implementing it or forwarding the message to an object that does know how to.
#import <stdio.h>
output
hello world
http://www.otierney.net/objective-c.html Page 2 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
Creating classes
@interface
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Fraction.h
#import <Foundation/NSObject.h>
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end
NSObject: Short for NeXTStep Object. Although this is less meaningful today since
it's really OpenStep.
Inheritance is specified as Class: Parent, as seen with Fraction: NSObject.
Instance variables go between @interface Class: Parent { .... }
No access is set (protected, public, private). Default is protected. Setting the access
will be shown later
Instance methods follow after the member variables. The format is: scope (returnType)
methodName: (parameter1Type) parameter1Name;
scope refers to class or instance. instance methods begin with - class level
methods begin with +
Interface ends with @end
@implementation
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Fraction.m
#import "Fraction.h"
#import <stdio.h>
@implementation Fraction
-(void) print {
printf( "%i/%i", numerator, denominator );
}
-(int) denominator {
return denominator;
}
http://www.otierney.net/objective-c.html Page 3 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
-(int) numerator {
return numerator;
}
@end
Piecing it together
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
main.m
#import <stdio.h>
#import "Fraction.h"
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
// free memory
[frac release];
return 0;
}
output
http://www.otierney.net/objective-c.html Page 4 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
later.
The details...
Multiple Parameters
Up until this point I haven't showed any way to specify multiple parameters. It's not as
intuitive at first, but it's syntax is a welcome addition from Smalltalk
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Fraction.h
...
-(void) setNumerator: (int) n andDenominator: (int) d;
...
Fraction.m
...
-(void) setNumerator: (int) n andDenominator: (int) d {
numerator = n;
denominator = d;
}
...
main.m
#import <stdio.h>
#import "Fraction.h"
// combined set
[frac2 setNumerator: 1 andDenominator: 5];
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
// print it
printf( "Fraction 2 is: " );
[frac2 print];
printf( "\n" );
// free memory
[frac release];
[frac2 release];
return 0;
}
output
http://www.otierney.net/objective-c.html Page 5 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
Constructors
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Fraction.h
...
-(Fraction*) initWithNumerator: (int) n denominator: (int) d;
...
Fraction.m
...
-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
self = [super init];
if ( self ) {
[self setNumerator: n andDenominator: d];
}
return self;
}
...
main.m
#import <stdio.h>
#import "Fraction.h"
// combined set
[frac2 setNumerator: 1 andDenominator: 5];
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
http://www.otierney.net/objective-c.html Page 6 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
[frac3 print];
printf( "\n" );
// free memory
[frac release];
[frac2 release];
[frac3 release];
return 0;
}
output
Access Privledges
The default access is @protected
Java implements this with public/private/protected modifiers infront of methods and
variables. Objective-C's approach is much more similar to C++'s for instance variables
Access.h
#import <Foundation/NSObject.h>
Access.m
#import "Access.h"
@implementation Access
@end
main.m
http://www.otierney.net/objective-c.html Page 7 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
#import "Access.h"
#import <stdio.h>
// works
a->publicVar = 5;
printf( "public var: %i\n", a->publicVar );
// doesn't compile
//a->privateVar = 10;
//printf( "private var: %i\n", a->privateVar );
[a release];
return 0;
}
output
public var: 5
As you an see, instead of private: [list of vars] public: [list of vars] like in C++, it's just
@private, @protected, etc.
#import <Foundation/NSObject.h>
ClassA.m
#import "ClassA.h"
@implementation ClassA
-(id) init {
self = [super init];
count++;
return self;
}
+(int) initCount {
return count;
}
+(void) initialize {
count = 0;
}
@end
main.m
#import "ClassA.h"
http://www.otierney.net/objective-c.html Page 8 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
#import <stdio.h>
// print count
printf( "ClassA count: %i\n", [ClassA initCount] );
[c1 release];
[c2 release];
[c3 release];
return 0;
}
output
ClassA count: 2
ClassA count: 3
static int count = 0; This is how the class variable is declared. This is not the ideal
place for such a variable. A nicer solution would have been like Java's implementation
of static class variables. However this works
+(int) initCount; This is the actual method that returns the count. Notice the subtle
difference. Instead of using a - infront of the type, a + is used. The + denotes a class
level function.
Accessing the variable is no different than member variables, as seen by count++ in
the constructor of ClassA.
The +(void) initialize method is called when Objective-C starts your program, and it's
called for every class. This is a good place to initialize class level variables like our
count.
Exceptions
NOTE: Exception handling is only supported in Mac OS X 10.3
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
CupWarningException.h
#import <Foundation/NSException.h>
CupWarningException.m
#import "CupWarningException.h"
@implementation CupWarningException
@end
CupOverflowException.h
#import <Foundation/NSException.h>
http://www.otierney.net/objective-c.html Page 9 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
CupOverflowException.m
#import "CupOverflowException.h"
@implementation CupOverflowException
@end
Cup.h
#import <Foundation/NSObject.h>
-(int) level;
-(void) setLevel: (int) l;
-(void) fill;
-(void) empty;
-(void) print;
@end
Cup.m
#import "Cup.h"
#import "CupOverflowException.h"
#import "CupWarningException.h"
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
@implementation Cup
-(id) init {
self = [super init];
if ( self ) {
[self setLevel: 0];
}
return self;
}
-(int) level {
return level;
}
http://www.otierney.net/objective-c.html Page 10 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
// throw exception
NSException *e = [NSException
exceptionWithName: @"CupUnderflowException"
reason: @"The level is below 0"
userInfo: nil];
@throw e;
}
}
-(void) fill {
[self setLevel: level + 10];
}
-(void) empty {
[self setLevel: level - 10];
}
-(void) print {
printf( "Cup level is: %i\n", level );
}
@end
main.m
#import "Cup.h"
#import "CupOverflowException.h"
#import "CupWarningException.h"
#import <Foundation/NSString.h>
#import <Foundation/NSException.h>
#import <Foundation/NSAutoreleasePool.h>
#import <stdio.h>
// free memory
[cup release];
[pool release];
}
http://www.otierney.net/objective-c.html Page 11 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
output
NSAutoreleasePool is a memory management class. Don't worry about what this does
right now.
Exceptions that are thrown don't have to extend NSException. You can just as easily
use an id as well: @catch ( id e ) { ... }
There is also a finally block, which behaves just like Java's. The contents of a finally
block are guaranteed to be called.
The string as show in Cup.m, @"CupOverflowException", is a constant NSString
object. The @ sign is used often in Objective-C to denote extentions to the language.
A C string is just like C and C++, "String constant", and is of type char *.
#import <Foundation/NSObject.h>
Fraction.m
#import "Fraction.h"
#import <stdio.h>
http://www.otierney.net/objective-c.html Page 12 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
@implementation Fraction
-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
self = [super init];
if ( self ) {
[self setNumerator: n andDenominator: d];
}
return self;
}
-(void) print {
printf( "%i / %i", numerator, denominator );
}
-(int) denominator {
return denominator;
}
-(int) numerator {
return numerator;
}
@end
Complex.h
#import <Foundation/NSObject.h>
@end
Complex.m
#import "Complex.h"
#import <stdio.h>
@implementation Complex
-(Complex*) initWithReal: (double) r andImaginary: (double) i {
self = [super init];
if ( self ) {
http://www.otierney.net/objective-c.html Page 13 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
return self;
}
-(double) real {
return real;
}
-(double) imaginary {
return imaginary;
}
-(void) print {
printf( "%_f + %_fi", real, imaginary );
}
@end
main.m
#import <stdio.h>
#import "Fraction.h"
#import "Complex.h"
// print fraction
number = frac;
printf( "The fraction is: " );
[number print];
printf( "\n" );
// print complex
number = comp;
printf( "The complex number is: " );
[number print];
printf( "\n" );
// free memory
[frac release];
[comp release];
return 0;
}
output
http://www.otierney.net/objective-c.html Page 14 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
There are obvious benefits to this type of dynamic binding. You don't have to know
the type of something to call a method on it. If the object responds to a message, it
will invoke that method. Lots of nasty casting isn't involved in this either, such as in
Java to call .intValue() on an integer object would involve casting first, then calling
the method.
Inheritance
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Rectangle.h
#import <Foundation/NSObject.h>
Rectangle.m
#import "Rectangle.h"
#import <stdio.h>
@implementation Rectangle
-(Rectangle*) initWithWidth: (int) w height: (int) h {
self = [super init];
if ( self ) {
[self setWidth: w height: h];
}
return self;
}
-(int) width {
return width;
}
-(int) height {
http://www.otierney.net/objective-c.html Page 15 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
return height;
}
-(void) print {
printf( "width = %i, height = %i", width, height );
}
@end
Square.h
#import "Rectangle.h"
Square.m
#import "Square.h"
@implementation Square
-(Square*) initWithSize: (int) s {
self = [super init];
if ( self ) {
[self setSize: s];
}
return self;
}
-(int) size {
return width;
}
main.m
#import "Square.h"
#import "Rectangle.h"
#import <stdio.h>
// print em
printf( "Rectangle: " );
[rec print];
printf( "\n" );
http://www.otierney.net/objective-c.html Page 16 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
// update square
[sq setWidth: 20];
printf( "Square after change: " );
[sq print];
printf( "\n" );
// free memory
[rec release];
[sq release];
return 0;
}
output
Inheritance in Objective-C is similar to Java. When you extend your super class (of
which you can only have one parent) you can override the methods of your super
class by simply putting the new implementations in the child classes implementation.
No fooling with virtual tables like C++.
One thing left out here that is worth nothing is what would happen if you attempted to
call the constructor for rectangle like: Square *sq = [[Square alloc] initWithWidth: 10
height: 15]. The answer is it will throw a compile error. Since the return type of the
rectangle constructor is Rectangle*, not Square* this would not work. In such a case if
you want this to occur, that's what the id variable is good for. Just change the
Rectangle* return type to id if you wish to use your parent's constructors in a subclass.
Dynamic types
There are several methods for working with dynamic types in Objective-C
is object a descendent or
-(BOOL) isKindOfClass: classObj
member of classObj
-(BOOL) isMemberOfClass: classObj is object a member of classObj
does the object have a method
-(BOOL) respondsToSelector: selector
named specifiec by the selector
does an object created by this
+(BOOL) instancesRespondToSelector:
class have the ability to respond
selector
to the specified selector
invoke the specified selector on
-(id) performSelector: selector
the object
Every object inherited from NSObject has a class method that returns a class object.
This is very similar to Java's getClass() method. This class object is used in the
methods above.
Selectors are used to represent a message in Objective-C. The syntax for creating a
selector is shown in the next example
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
main.m
#import "Square.h"
#import "Rectangle.h"
http://www.otierney.net/objective-c.html Page 17 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
#import <stdio.h>
// isMemberOfClass
// true
if ( [sq isMemberOfClass: [Square class]] == YES ) {
printf( "square is a member of square class\n" );
}
// false
if ( [sq isMemberOfClass: [Rectangle class]] == YES ) {
printf( "square is a member of rectangle class\n" );
}
// false
if ( [sq isMemberOfClass: [NSObject class]] == YES ) {
printf( "square is a member of object class\n" );
}
// isKindOfClass
// true
if ( [sq isKindOfClass: [Square class]] == YES ) {
printf( "square is a kind of square class\n" );
}
// true
if ( [sq isKindOfClass: [Rectangle class]] == YES ) {
printf( "square is a kind of rectangle class\n" );
}
// true
if ( [sq isKindOfClass: [NSObject class]] == YES ) {
printf( "square is a kind of object class\n" );
}
// respondsToSelector
// true
if ( [sq respondsToSelector: @selector( setSize: )] == YES ) {
printf( "square responds to setSize: method\n" );
}
// false
if ( [sq respondsToSelector: @selector( nonExistant )] == YES ) {
printf( "square responds to nonExistant method\n" );
}
// true
if ( [Square respondsToSelector: @selector( alloc )] == YES ) {
printf( "square class responds to alloc method\n" );
}
// instancesRespondToSelector
// false
if ( [Rectangle instancesRespondToSelector: @selector( setSize: )] == YES ) {
printf( "rectangle instance responds to setSize: method\n" );
}
// true
if ( [Square instancesRespondToSelector: @selector( setSize: )] == YES ) {
printf( "square instance responds to setSize: method\n" );
}
http://www.otierney.net/objective-c.html Page 18 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
// free memory
[rec release];
[sq release];
return 0;
}
output
Categories
When you want to add methods to a class, you typically extend it. However this
solution isn't always perfect, especially if you want to rewrite the functionality of a
class that you don't have the source code to. Categories allow you to add functionality
to already existing classes without extending them. Ruby also has similar functionality
to this.
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
FractionMath.h
#import "Fraction.h"
FractionMath.m
#import "FractionMath.h"
http://www.otierney.net/objective-c.html Page 19 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
main.m
#import <stdio.h>
#import "Fraction.h"
#import "FractionMath.h"
// print it
[frac1 print];
printf( " * " );
[frac2 print];
printf( " = " );
[frac3 print];
printf( "\n" );
// free memory
[frac1 release];
[frac2 release];
[frac3 release];
return 0;
}
output
The magic here is the two @implementation and @interface lines: @interface Fraction
(Math) and @implementation Fraction (Math).
There can only be one category with the same name. Additional cateogies may be
added on with different but unqiue names.
Categories can't add instance variables.
Categories are useful for creating private methods. Since Objective-C has no notion of
private/protected/public methods like java does, one has to create categories that hide
such functionality. The way this is done is by moving the private methods from your
class's header (.h) file to the implementation file (.m). The following is a very brief
example of what I mean.
MyClass.h
#import <Foundation/NSObject.h>
MyClass.m
#import "MyClass.h"
#import <stdio.h>
@implementation MyClass
-(void) publicMethod {
printf( "public method\n" );
}
http://www.otierney.net/objective-c.html Page 20 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
@end
// private methods
@interface MyClass (Private)
-(void) privateMethod;
@end
main.m
#import "MyClass.h"
// this compiles
[obj publicMethod];
// free memory
[obj release];
return 0;
}
output
public method
Posing
Posing is similar to categories, but with a twist. It allows you to extend a class, and
make your subclass pose (in place of) the super class globally. For instance: Say you
have NSArrayChild that extends NSArray. If you made NSArrayChild pose for
NSArray all your code would begin using the NSArrayChild instead of NSArray
automatically.
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
FractionB.h
#import "Fraction.h"
FractionB.m
#import "FractionB.h"
#import <stdio.h>
@implementation FractionB
-(void) print {
printf( "(%i/%i)", numerator, denominator );
}
http://www.otierney.net/objective-c.html Page 21 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
@end
main.m
#import <stdio.h>
#import "Fraction.h"
#import "FractionB.h"
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
// print it
printf( "The fraction is: " );
[frac2 print];
printf( "\n" );
// free memory
[frac release];
[frac2 release];
return 0;
}
output
The output from this program would print the first fraction s 3/10. The second would
output (3/10), which is implemented by FractionB.
The method poseAsClass is part of NSObject. This allows a subclass to pose as a
superclass.
Protocols
A Protocol in Objective-C is identical in functionality to an interface in Java, or a
purely virtual class in C++.
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Printing.h
@protocol Printing
-(void) print;
@end
Fraction.h
#import <Foundation/NSObject.h>
#import "Printing.h"
http://www.otierney.net/objective-c.html Page 22 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
int denominator;
}
Fraction.m
#import "Fraction.h"
#import <stdio.h>
@implementation Fraction
-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
self = [super init];
if ( self ) {
[self setNumerator: n andDenominator: d];
}
return self;
}
-(void) print {
printf( "%i/%i", numerator, denominator );
}
-(int) denominator {
return denominator;
}
-(int) numerator {
return numerator;
}
Complex.h
#import <Foundation/NSObject.h>
#import "Printing.h"
http://www.otierney.net/objective-c.html Page 23 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
Complex.m
#import "Complex.h"
#import <stdio.h>
@implementation Complex
-(Complex*) initWithReal: (double) r andImaginary: (double) i {
self = [super init];
if ( self ) {
[self setReal: r andImaginary: i];
}
return self;
}
-(double) real {
return real;
}
-(double) imaginary {
return imaginary;
}
-(void) print {
printf( "%_f + %_fi", real, imaginary );
}
@end
main.m
#import <stdio.h>
#import "Fraction.h"
#import "Complex.h"
// print it
printable = frac;
printf( "The fraction is: " );
http://www.otierney.net/objective-c.html Page 24 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
[printable print];
printf( "\n" );
// print complex
printable = comp;
printf( "The complex number is: " );
[printable print];
printf( "\n" );
// test conformance
// true
if ( [frac conformsToProtocol: @protocol( NSCopying )] == YES ) {
printf( "Fraction conforms to NSCopying\n" );
}
// false
if ( [comp conformsToProtocol: @protocol( NSCopying )] == YES ) {
printf( "Complex conforms to NSCopying\n" );
}
// free memory
[frac release];
[comp release];
return 0;
}
output
Memory Management
http://www.otierney.net/objective-c.html Page 25 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
Up until now I've kind of dodged memory management in Objective-C. Sure you can call
dealloc on an object, but what happens if the object contains pointers to other objects? One
has to be concerned about freeing the memory of those objects as well. Also how does the
Foundation framework manage memory when you create classes from it? This will all be
explained.
Note: everything up until this point has been properly memory managed, incase you're
wondering.
...
-(void) dealloc {
printf( "Deallocing fraction\n" );
[super dealloc];
}
...
#import "Fraction.h"
#import <stdio.h>
// increment them
[frac1 retain]; // 2
[frac1 retain]; // 3
[frac2 retain]; // 2
// decrement
[frac1 release]; // 2
[frac2 release]; // 1
http://www.otierney.net/objective-c.html Page 26 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
output
The retain calls increment the counter. The release calls decrement it. One can get the
count as an int by calling [obj retainCount]. Once the retainCount reaches 0, both
objects dealloc themselves and you can see this when both print out "Deallocing
fraction."
Dealloc
When your object contains other objects, you must free them whenever you yourself
dealloc. One of the nice advantages to Objective-C is you can pass messages to nil, so
there isn't a lot of error checking to release an object.
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
AddressCard.h
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
AddressCard.m
#import "AddressCard.h"
#import <stdio.h>
@implementation AddressCard
-(AddressCard*) initWithFirst: (NSString*) f
last: (NSString*) l
email: (NSString*) e {
self = [super init];
http://www.otierney.net/objective-c.html Page 27 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
if ( self ) {
[self setFirst: f last: l email: e];
}
return self;
}
-(NSString*) first {
return first;
}
-(NSString*) last {
return last;
}
-(NSString*) email {
return email;
}
-(void) print {
printf( "%s %s <%s>", [first cString],
[last cString],
[email cString] );
}
-(void) dealloc {
[first release];
[last release];
[email release];
[super dealloc];
}
@end
main.m
http://www.otierney.net/objective-c.html Page 28 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
#import "AddressCard.h"
#import <Foundation/NSString.h>
#import <stdio.h>
// free memory
[tom release];
return 0;
}
output
Retain count: 1
Tom Jones <[email protected]>
This example shows not only how to make a dealloc method, as shown in
AddressCard.m, but one way to do member variables.
The order of the 3 operations in each set method is very important. Lets say you'return
passing a parameter of yourself to one of your methods (a bit of an odd example, but
this can happen). If you release first, THEN retain you will destruct yourself! That's
why you should always 1) retain 2) release 3) set the value.
Normally one wouldn't initialize variables with C strings because they don't support
unicode. The next example, with NSAutoreleasePool shows the proper way to do
strings and initializing.
This is just one way of handling member variable memory management. One way to
handle this is to create copies inside your set methods.
Autorelease Pool
When you want to start doing more programming using NSString and other
Foundation framework classes you need a more flexible system. This system is using
Autorelease pools.
When developing Mac Cocoa applications, the auto release pool is setup automatically
for you.
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
main.m
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
#import <stdio.h>
http://www.otierney.net/objective-c.html Page 29 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
// free memory
[str3 release];
// free pool
[pool release];
return 0;
}
output
If you run this you'll notice a few things. One is that the retainCount of str1 is ffffffff.
The other is, I only release str3, yet this program is memory management perfect. The
reason is the first constant string is added to the autorelease pool automatically. The
other string is made using stringWithString. This method creates a string that is owned
by NSString class, which also puts it in the auto release pool.
It's important to remember, for proper memory management, that convience methods
like [NSString stringWithString: @"String"] use autorelease pools, but alloc methods
like [[NSString alloc] initWithString: @"String"] do not use autorelease pools for
managing memory.
There are two ways to manage memory in Objective-C: 1) retain and release or 2)
retain and release/autorelease.
For each retain, there must be one release OR one autorelease.
The following example shows what I mean by this
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
Fraction.h
...
+(Fraction*) fractionWithNumerator: (int) n denominator: (int) d;
...
Fraction.m
...
+(Fraction*) fractionWithNumerator: (int) n denominator: (int) d {
Fraction *ret = [[Fraction alloc] initWithNumerator: n denominator: d];
[ret autorelease];
return ret;
}
...
main.m
#import <Foundation/NSAutoreleasePool.h>
#import "Fraction.h"
#import <stdio.h>
http://www.otierney.net/objective-c.html Page 30 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
// print frac 1
printf( "Fraction 1: " );
[frac1 print];
printf( "\n" );
// print frac 2
printf( "Fraction 2: " );
[frac2 print];
printf( "\n" );
output
Fraction 1: 2/5
Fraction 2: 1/3
In this example, the method is a class level method. After the object is created,
autorelease is called on it. Inside the body of the main method, I never call release on
the object.
The reason this works is because: for every retain, one release or autorelease must be
called. The object's retain count starts out as 1, and I called autorelease on it once.
This means 1 - 1 = 0. Once the autorelease pool is released, it counts the autorelease
calls on all objects and decrements them with [obj release] with the same number of
times autorelease was called per object.
As the comment says, uncommenting that line causes a segment fault. Since
autorelease was already called on the object, calling release on it, and then releasing
the autorelease pool would attempt to call dealloc on an object that is nil, which is not
valid. The end math is 1 (creation) - 1 (release) - 1 (autorelease) = -1.
Auto release pools can be dynamically created for large amounts of temporary objects.
All one must do is create a pool, perform any large chunk of code that creates lots of
temporary objects, then release the pool. As you may wonder, it this means it is
possible to have more than one auto release pool at a time.
NSArray
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
main.m
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
http://www.otierney.net/objective-c.html Page 31 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
#import <Foundation/NSEnumerator.h>
#import <stdio.h>
// add stuff
[mutable addObject: @"One"];
[mutable addObject: @"Two"];
[mutable addObjectsFromArray: arr];
[mutable addObject: @"Three"];
// print em
printf( "----mutable array\n" );
print( mutable );
// free memory
[arr release];
[mutable release];
[pool release];
return 0;
}
output
----static array
Me
Myself
I
----mutable array
One
Two
Me
Myself
I
Three
----sorted mutable array
I
Me
Myself
One
Three
Two
There are two kinds of arrays (and of usually most data oriented Foundation classes)
http://www.otierney.net/objective-c.html Page 32 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
NSDictionary
Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams
Publishing. Used with permission
main.m
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/Foundation.h<
#import <stdio.h>
// print dictionary
printf( "----static dictionary\n" );
print( dictionary );
// add objects
[mutable setObject: @"Tom" forKey: @"[email protected]"];
[mutable setObject: @"Bob" forKey: @"[email protected]" ];
// free memory
[dictionary release];
[mutable release];
http://www.otierney.net/objective-c.html Page 33 of 34
Objective-C Beginner's Guide 25/8/09 6:56 am
[pool release];
return 0;
}
output
----static dictionary
1 => one
2 => two
3 => three
----mutable dictionary
[email protected] => Bob
[email protected] => Tom
Cons
No namespaces
No operator overloading (this is often considered a Pro though, but operator
overloading used properly can reduce code clutter)
Still some cruft in language, although no more than C++
More Information
Object-Oriented Programming and the Objective-C Language
GNUstep mini tutorials
Programming in Objective-C
Learning Cocoa with Objective-C
Cocoa Programming for Mac OS X
http://www.otierney.net/objective-c.html Page 34 of 34