objective c beginner's guide

34
24/11/10 21:11 Objective-C Beginner's Guide Página 1 de 34 http://www.otierney.net/objective-c.html Translations: English | Chinese | Korean 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. Setting up the environment Linux/FreeBSD: Install GNUStep In order to build GNUstep applications one must first execute the GNUstep.sh file in /usr/GNUstep/System/Makefiles/GNUstep.sh. This path depends on your

Upload: tiago-faller

Post on 02-Jul-2015

870 views

Category:

Documents


0 download

DESCRIPTION

Guia fácil e prático de Objective-C.Fonte: http://www.otierney.net/objective-c.html

TRANSCRIPT

Page 1: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 1 de 34http://www.otierney.net/objective-c.html

Translations: English | Chinese | Korean

OutlineGetting Started

Downloading this tutorialSetting up the environmentPreambleMaking hello world

Creating Classes@interface@implementationPiecing it together

The Details...Multiple ParametersConstructorsAccess PrivledgesClass level accessExceptions

Inheritance, Polymorphism, and other OOP featuresThe id typeInheritanceDynamic typesCategoriesPosingProtocols

Memory ManagementRetain and ReleaseDeallocAutorelease Pool

Foundation Framework ClassesNSArrayNSDictionary

Pros and ConsMore Information

Getting StartedDownloading this tutorial

All the source code for this beginners guide including makefiles is available bydownloading objc.tar.gz. Many of the examples in this tutorial were written by SteveKochan in the book Programming in Objective-C. If you want more detailedinformation and examples, feel free to check out his book. The examples on this sitewere used with his permission, so please don't copy them.

Setting up the environmentLinux/FreeBSD: Install GNUStep

In order to build GNUstep applications one must first execute the GNUstep.shfile in /usr/GNUstep/System/Makefiles/GNUstep.sh. This path depends on your

Page 2: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 2 de 34http://www.otierney.net/objective-c.html

system. Some put it in /usr, some /usr/lib, some /usr/local. If your shell is acsh/tcsh based shell, you'll want to execute GNUStep.csh instead. It'srecommended that you put this script in your .bashrc or .cshrc.

Mac OS X: Install XCodeWindows NT 5.X: Install cygwin or mingw and then install GNUStep

PreambleThis tutorial assumes you have some basic C knowledge, including C data types, whata function is, what a return value is, knowledge of pointers and basic memorymanagement in C. If you haven't gotten this far, I highly suggest you pick up K andR's book, The C Programming Language. This is the book on C written by the writersof C.Objective-C, being a C derivative, inherits all of C's features. There are a fewexceptions 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 isyou can pass messages to nil (such as [nil message];) and this is perfectly legal. Youcannot 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 importingNSObject.h). nil is also included in this header file. BOOL in Objective-C has twomodes, 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 andbottom of every .h file you make. I find this to be retarded, as many otherprogrammers 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 toeither keep it from getting removed or getting added back in. As an aside, Appleofficially uses #import in all their code so if this ever did happen, you can be certainthat 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, althoughmessages have special properties. A message can be dynamically forwarded to anotherobject. Calling a message on an object in Objective-C doesn't mean that the objectimplements that message, just that it knows how to respond to it somehow via directlyimplementing it or forwarding the message to an object that does know how to.

Making hello worldhello.m

#import <stdio.h>

int main( int argc, const char *argv[] ) { printf( "hello world\n" ); return 0;}

output

hello world

You use #import instead of #include in Objective-CThe default file extention for Objective-C is .m

Page 3: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 3 de 34http://www.otierney.net/objective-c.html

Creating classes@interface

Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFraction.h

#import <Foundation/NSObject.h>

@interface Fraction: NSObject { int numerator; int denominator;}

-(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 sinceit'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 accesswill be shown laterInstance 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 levelmethods begin with +

Interface ends with @end

@implementationBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFraction.m

#import "Fraction.h"#import <stdio.h>

@implementation Fraction-(void) print { printf( "%i/%i", numerator, denominator );}

-(void) setNumerator: (int) n { numerator = n;}

-(void) setDenominator: (int) d { denominator = d;}

-(int) denominator { return denominator;}

Page 4: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 4 de 34http://www.otierney.net/objective-c.html

-(int) numerator { return numerator;}@end

@implementation ClassName starts the implementation @end ends itAll the defined methods are implemented very simlar to how they are declared in theinterface

Piecing it togetherBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionmain.m

#import <stdio.h>#import "Fraction.h"

int main( int argc, const char *argv[] ) { // create a new instance Fraction *frac = [[Fraction alloc] init];

// set the values [frac setNumerator: 1]; [frac setDenominator: 3];

// print it printf( "The fraction is: " ); [frac print]; printf( "\n" );

// free memory [frac release];

return 0;}

output

The fraction is: 1/3

Fraction *frac = [[Fraction alloc] init];There are several important things in this one line.The way methods in Objective-C are called is [object method], which is similarto object->method() in C++Objective-C doesn't have value types, so there is nothing similar to C++'s:Fraction frac; frac.print();. You always deal with objects as pointers inObjective-C.What this line is really doing is two things: [Fraction alloc] is calling the allocmethod on the Fraction class. This is similar to mallocing memory, because thatis all that is done in this operation.[object init] is the constructor call, which initializes any variables in the object.This method is called on the instance returned from [Fraction alloc]. Thisoperation is so common it's usually just done in one line as Object *var =[[Object alloc] init];

[frac setNumerator: 1] is quite simple. It's calling the setNumerator method on frac,and passing it the parameter 1.Like every c variant, there's a construct for freeing memory. This is done via release,which is inherited from NSObject. This method will be explainted in greater detail

Page 5: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 5 de 34http://www.otierney.net/objective-c.html

later.

The details...Multiple Parameters

Up until this point I haven't showed any way to specify multiple parameters. It's not asintuitive at first, but it's syntax is a welcome addition from SmalltalkBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFraction.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"

int main( int argc, const char *argv[] ) { // create a new instance Fraction *frac = [[Fraction alloc] init]; Fraction *frac2 = [[Fraction alloc] init];

// set the values [frac setNumerator: 1]; [frac setDenominator: 3];

// 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

Page 6: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 6 de 34http://www.otierney.net/objective-c.html

The fraction is: 1/3Fraction 2 is: 1/5

The method is actually called setNumerator:andDenominator:Additional parameters are added the same was as the 2nd, such that you'd havemethod:label1:label2:label3: and you'd call it with [obj method: param1 label1:param2 label2: param3 label3: param4]Labels are optional. It's possible to have a method named method:::. This is done bysimply not specifing label names, but just a : to separate the parameters. This ishowever not advised.

ConstructorsBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFraction.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"

int main( int argc, const char *argv[] ) { // create a new instance Fraction *frac = [[Fraction alloc] init]; Fraction *frac2 = [[Fraction alloc] init]; Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

// set the values [frac setNumerator: 1]; [frac setDenominator: 3];

// combined set [frac2 setNumerator: 1 andDenominator: 5];

// print it printf( "The fraction is: " ); [frac print]; printf( "\n" );

printf( "Fraction 2 is: " ); [frac2 print]; printf( "\n" );

printf( "Fraction 3 is: " );

Page 7: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 7 de 34http://www.otierney.net/objective-c.html

[frac3 print]; printf( "\n" );

// free memory [frac release]; [frac2 release]; [frac3 release];

return 0;}

output

The fraction is: 1/3Fraction 2 is: 1/5Fraction 3 is: 3/10

@interface declaration is identical to a regular function@implementation shows a new keyword: super

Similar to Java, Objective-C only has one parent class.Accessing it's super constructor is done through [super init] and this is requiredfor proper inheritance.This returns an instance which you assign to another new keyword, self. Self issimilar to this in Java and C++.

if ( self ) is the same as if ( self != nil ) to make sure that the super constructorsuccessfully returned a new object. nil is Objective-C's form of NULL from C/C++.This is gotten from including NSObject.After you've initialized the varialbes, you return yourself with return self;The deafult constructor is -(id) init;Constructors in Objective-C are technically just "init" methods, they aren't a specialconstruct like they are in C++ and Java.

Access PrivledgesThe default access is @protectedJava implements this with public/private/protected modifiers infront of methods andvariables. Objective-C's approach is much more similar to C++'s for instance variablesAccess.h

#import <Foundation/NSObject.h>

@interface Access: NSObject {@public int publicVar;@private int privateVar; int privateVar2;@protected int protectedVar;}@end

Access.m

#import "Access.h"

@implementation Access@end

main.m

Page 8: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 8 de 34http://www.otierney.net/objective-c.html

#import "Access.h"#import <stdio.h>

int main( int argc, const char *argv[] ) { Access *a = [[Access alloc] init];

// 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.

Class level accessOften it's nice to have class level variables and functions, for instance when keepingtrack of the # of times an object has been instanciated.ClassA.h

#import <Foundation/NSObject.h>

static int count;

@interface ClassA: NSObject+(int) initCount;+(void) initialize;@end

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"

Page 9: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 9 de 34http://www.otierney.net/objective-c.html

#import <stdio.h>

int main( int argc, const char *argv[] ) { ClassA *c1 = [[ClassA alloc] init]; ClassA *c2 = [[ClassA alloc] init];

// print count printf( "ClassA count: %i\n", [ClassA initCount] ); ClassA *c3 = [[ClassA alloc] init];

// print count again printf( "ClassA count: %i\n", [ClassA initCount] );

[c1 release]; [c2 release]; [c3 release]; return 0;}

output

ClassA count: 2ClassA count: 3

static int count = 0; This is how the class variable is declared. This is not the idealplace for such a variable. A nicer solution would have been like Java's implementationof static class variables. However this works+(int) initCount; This is the actual method that returns the count. Notice the subtledifference. Instead of using a - infront of the type, a + is used. The + denotes a classlevel function.Accessing the variable is no different than member variables, as seen by count++ inthe constructor of ClassA.The +(void) initialize method is called when Objective-C starts your program, and it'scalled for every class. This is a good place to initialize class level variables like ourcount.

ExceptionsNOTE: Exception handling is only supported in Mac OS X 10.3Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionCupWarningException.h

#import <Foundation/NSException.h>

@interface CupWarningException: NSException@end

CupWarningException.m

#import "CupWarningException.h"

@implementation CupWarningException@end

CupOverflowException.h

#import <Foundation/NSException.h>

Page 10: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 10 de 34http://www.otierney.net/objective-c.html

@interface CupOverflowException: NSException@end

CupOverflowException.m

#import "CupOverflowException.h"

@implementation CupOverflowException@end

Cup.h

#import <Foundation/NSObject.h>

@interface Cup: NSObject { int level;}

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

-(void) setLevel: (int) l { level = l;

if ( level > 100 ) { // throw overflow NSException *e = [CupOverflowException exceptionWithName: @"CupOverflowException" reason: @"The level is above 100" userInfo: nil]; @throw e; } else if ( level >= 50 ) { // throw warning NSException *e = [CupWarningException exceptionWithName: @"CupWarningException" reason: @"The level is above or at 50" userInfo: nil]; @throw e; } else if ( level < 0 ) {

Page 11: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 11 de 34http://www.otierney.net/objective-c.html

// 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>

int main( int argc, const char *argv[] ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Cup *cup = [[Cup alloc] init]; int i;

// this will work for ( i = 0; i < 4; i++ ) { [cup fill]; [cup print]; }

// this will throw exceptions for ( i = 0; i < 7; i++ ) { @try { [cup fill]; } @catch ( CupWarningException *e ) { printf( "%s: ", [[e name] cString] ); } @catch ( CupOverflowException *e ) { printf( "%s: ", [[e name] cString] ); } @finally { [cup print]; } }

// throw a generic exception @try { [cup setLevel: -1]; } @catch ( NSException *e ) { printf( "%s: %s\n", [[e name] cString], [[e reason] cString] ); }

// free memory [cup release]; [pool release];}

Page 12: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 12 de 34http://www.otierney.net/objective-c.html

output

Cup level is: 10Cup level is: 20Cup level is: 30Cup level is: 40CupWarningException: Cup level is: 50CupWarningException: Cup level is: 60CupWarningException: Cup level is: 70CupWarningException: Cup level is: 80CupWarningException: Cup level is: 90CupWarningException: Cup level is: 100CupOverflowException: Cup level is: 110CupUnderflowException: The level is below 0

NSAutoreleasePool is a memory management class. Don't worry about what this doesright now.Exceptions that are thrown don't have to extend NSException. You can just as easilyuse an id as well: @catch ( id e ) { ... }There is also a finally block, which behaves just like Java's. The contents of a finallyblock are guaranteed to be called.The string as show in Cup.m, @"CupOverflowException", is a constant NSStringobject. 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 *.

Inheritance, Polymorphism, and other OOPfeatures

The id typeObjective-C has a type called id, that acts in some ways like a void*, though it's meantstrictly for objects. Objective-C differs from Java and C++ in that when you call amethod on an object, it doesn't need to know the type. That method simply just has toexist. This is refered to as message pasing in Objective-C.Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFraction.h

#import <Foundation/NSObject.h>

@interface Fraction: NSObject { int numerator; int denominator;}

-(Fraction*) initWithNumerator: (int) n denominator: (int) d;-(void) print;-(void) setNumerator: (int) d;-(void) setDenominator: (int) d;-(void) setNumerator: (int) n andDenominator: (int) d;-(int) numerator;-(int) denominator;@end

Fraction.m

#import "Fraction.h"#import <stdio.h>

Page 13: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 13 de 34http://www.otierney.net/objective-c.html

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

-(void) setNumerator: (int) n { numerator = n;}

-(void) setDenominator: (int) d { denominator = d;}

-(void) setNumerator: (int) n andDenominator: (int) d { numerator = n; denominator = d;}

-(int) denominator { return denominator;}

-(int) numerator { return numerator;}@end

Complex.h

#import <Foundation/NSObject.h>

@interface Complex: NSObject { double real; double imaginary;}

-(Complex*) initWithReal: (double) r andImaginary: (double) i;-(void) setReal: (double) r;-(void) setImaginary: (double) i;-(void) setReal: (double) r andImaginary: (double) i;-(double) real;-(double) imaginary;-(void) print;

@end

Complex.m

#import "Complex.h"#import <stdio.h>

@implementation Complex-(Complex*) initWithReal: (double) r andImaginary: (double) i { self = [super init];

if ( self ) {

Page 14: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 14 de 34http://www.otierney.net/objective-c.html

[self setReal: r andImaginary: i]; }

return self;}

-(void) setReal: (double) r { real = r;}

-(void) setImaginary: (double) i { imaginary = i;}

-(void) setReal: (double) r andImaginary: (double) i { real = r; imaginary = i;}

-(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"

int main( int argc, const char *argv[] ) { // create a new instance Fraction *frac = [[Fraction alloc] initWithNumerator: 1 denominator: 10]; Complex *comp = [[Complex alloc] initWithReal: 10 andImaginary: 15]; id number;

// 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

The fraction is: 1 / 10

Page 15: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 15 de 34http://www.otierney.net/objective-c.html

The complex number is: 10.000000 + 15.000000i

There are obvious benefits to this type of dynamic binding. You don't have to knowthe type of something to call a method on it. If the object responds to a message, itwill invoke that method. Lots of nasty casting isn't involved in this either, such as inJava to call .intValue() on an integer object would involve casting first, then callingthe method.

InheritanceBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionRectangle.h

#import <Foundation/NSObject.h>

@interface Rectangle: NSObject { int width; int height;}

-(Rectangle*) initWithWidth: (int) w height: (int) h;-(void) setWidth: (int) w;-(void) setHeight: (int) h;-(void) setWidth: (int) w height: (int) h;-(int) width;-(int) height;-(void) print;@end

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

-(void) setWidth: (int) w { width = w;}

-(void) setHeight: (int) h { height = h;}

-(void) setWidth: (int) w height: (int) h { width = w; height = h;}

-(int) width { return width;}

-(int) height {

Page 16: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 16 de 34http://www.otierney.net/objective-c.html

return height;}

-(void) print { printf( "width = %i, height = %i", width, height );}@end

Square.h

#import "Rectangle.h"

@interface Square: Rectangle-(Square*) initWithSize: (int) s;-(void) setSize: (int) s;-(int) size;@end

Square.m

#import "Square.h"

@implementation Square-(Square*) initWithSize: (int) s { self = [super init];

if ( self ) { [self setSize: s]; }

return self;}

-(void) setSize: (int) s { width = s; height = s;}

-(int) size { return width;}

-(void) setWidth: (int) w { [self setSize: w];}

-(void) setHeight: (int) h { [self setSize: h];}@end

main.m

#import "Square.h"#import "Rectangle.h"#import <stdio.h>

int main( int argc, const char *argv[] ) { Rectangle *rec = [[Rectangle alloc] initWithWidth: 10 height: 20]; Square *sq = [[Square alloc] initWithSize: 15];

// print em printf( "Rectangle: " ); [rec print]; printf( "\n" );

Page 17: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 17 de 34http://www.otierney.net/objective-c.html

printf( "Square: " ); [sq print]; printf( "\n" );

// update square [sq setWidth: 20]; printf( "Square after change: " ); [sq print]; printf( "\n" );

// free memory [rec release]; [sq release]; return 0;}

output

Rectangle: width = 10, height = 20Square: width = 15, height = 15Square after change: width = 20, height = 20

Inheritance in Objective-C is similar to Java. When you extend your super class (ofwhich you can only have one parent) you can override the methods of your superclass 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 tocall the constructor for rectangle like: Square *sq = [[Square alloc] initWithWidth: 10height: 15]. The answer is it will throw a compile error. Since the return type of therectangle constructor is Rectangle*, not Square* this would not work. In such a case ifyou want this to occur, that's what the id variable is good for. Just change theRectangle* return type to id if you wish to use your parent's constructors in a subclass.

Dynamic typesThere are several methods for working with dynamic types in Objective-C

-(BOOL) isKindOfClass: classObj is object a descendent ormember of classObj

-(BOOL) isMemberOfClass: classObj is object a member of classObj

-(BOOL) respondsToSelector: selector does the object have a methodnamed specifiec by the selector

+(BOOL) instancesRespondToSelector:selector

does an object created by thisclass have the ability to respondto the specified selector

-(id) performSelector: selector invoke the specified selector onthe 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 themethods above.Selectors are used to represent a message in Objective-C. The syntax for creating aselector is shown in the next exampleBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionmain.m

#import "Square.h"#import "Rectangle.h"

Page 18: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 18 de 34http://www.otierney.net/objective-c.html

#import <stdio.h>

int main( int argc, const char *argv[] ) { Rectangle *rec = [[Rectangle alloc] initWithWidth: 10 height: 20]; Square *sq = [[Square alloc] initWithSize: 15];

// 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" ); }

Page 19: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 19 de 34http://www.otierney.net/objective-c.html

// free memory [rec release]; [sq release]; return 0;}

output

square is a member of square classsquare is a kind of square classsquare is a kind of rectangle classsquare is a kind of object classsquare responds to setSize: methodsquare class responds to alloc methodsquare instance responds to setSize: method

CategoriesWhen you want to add methods to a class, you typically extend it. However thissolution isn't always perfect, especially if you want to rewrite the functionality of aclass that you don't have the source code to. Categories allow you to add functionalityto already existing classes without extending them. Ruby also has similar functionalityto this.Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFractionMath.h

#import "Fraction.h"

@interface Fraction (Math)-(Fraction*) add: (Fraction*) f;-(Fraction*) mul: (Fraction*) f;-(Fraction*) div: (Fraction*) f;-(Fraction*) sub: (Fraction*) f;@end

FractionMath.m

#import "FractionMath.h"

@implementation Fraction (Math)-(Fraction*) add: (Fraction*) f { return [[Fraction alloc] initWithNumerator: numerator * [f denominator] + denominator * [f numerator] denominator: denominator * [f denominator]];}

-(Fraction*) mul: (Fraction*) f { return [[Fraction alloc] initWithNumerator: numerator * [f numerator] denominator: denominator * [f denominator]];

}

-(Fraction*) div: (Fraction*) f { return [[Fraction alloc] initWithNumerator: numerator * [f denominator] denominator: denominator * [f numerator]];}

-(Fraction*) sub: (Fraction*) f { return [[Fraction alloc] initWithNumerator: numerator * [f denominator] - denominator * [f numerator]

Page 20: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 20 de 34http://www.otierney.net/objective-c.html

denominator: denominator * [f denominator]];}@end

main.m

#import <stdio.h>#import "Fraction.h"#import "FractionMath.h"

int main( int argc, const char *argv[] ) { // create a new instance Fraction *frac1 = [[Fraction alloc] initWithNumerator: 1 denominator: 3]; Fraction *frac2 = [[Fraction alloc] initWithNumerator: 2 denominator: 5]; Fraction *frac3 = [frac1 mul: frac2];

// print it [frac1 print]; printf( " * " ); [frac2 print]; printf( " = " ); [frac3 print]; printf( "\n" );

// free memory [frac1 release]; [frac2 release]; [frac3 release];

return 0;}

output

1/3 * 2/5 = 2/15

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 beadded 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 ofprivate/protected/public methods like java does, one has to create categories that hidesuch functionality. The way this is done is by moving the private methods from yourclass's header (.h) file to the implementation file (.m). The following is a very briefexample of what I mean.MyClass.h

#import <Foundation/NSObject.h>

@interface MyClass: NSObject-(void) publicMethod;@end

MyClass.m

#import "MyClass.h"#import <stdio.h>

@implementation MyClass-(void) publicMethod { printf( "public method\n" );}

Page 21: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 21 de 34http://www.otierney.net/objective-c.html

@end

// private methods@interface MyClass (Private)-(void) privateMethod;@end

@implementation MyClass (Private)-(void) privateMethod { printf( "private method\n" );}@end

main.m

#import "MyClass.h"

int main( int argc, const char *argv[] ) { MyClass *obj = [[MyClass alloc] init];

// this compiles [obj publicMethod];

// this throws errors when compiling //[obj privateMethod];

// free memory [obj release]; return 0;}

output

public method

PosingPosing is similar to categories, but with a twist. It allows you to extend a class, andmake your subclass pose (in place of) the super class globally. For instance: Say youhave NSArrayChild that extends NSArray. If you made NSArrayChild pose forNSArray all your code would begin using the NSArrayChild instead of NSArrayautomatically.Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFractionB.h

#import "Fraction.h"

@interface FractionB: Fraction-(void) print;@end

FractionB.m

#import "FractionB.h"#import <stdio.h>

@implementation FractionB-(void) print { printf( "(%i/%i)", numerator, denominator );}

Page 22: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 22 de 34http://www.otierney.net/objective-c.html

@end

main.m

#import <stdio.h>#import "Fraction.h"#import "FractionB.h"

int main( int argc, const char *argv[] ) { Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

// print it printf( "The fraction is: " ); [frac print]; printf( "\n" );

// make FractionB pose as Fraction [FractionB poseAsClass: [Fraction class]];

Fraction *frac2 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

// print it printf( "The fraction is: " ); [frac2 print]; printf( "\n" );

// free memory [frac release]; [frac2 release];

return 0;}

output

The fraction is: 3/10The fraction is: (3/10)

The output from this program would print the first fraction s 3/10. The second wouldoutput (3/10), which is implemented by FractionB.The method poseAsClass is part of NSObject. This allows a subclass to pose as asuperclass.

ProtocolsA Protocol in Objective-C is identical in functionality to an interface in Java, or apurely virtual class in C++.Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionPrinting.h

@protocol Printing-(void) print;@end

Fraction.h

#import <Foundation/NSObject.h>#import "Printing.h"

@interface Fraction: NSObject <Printing, NSCopying> { int numerator;

Page 23: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 23 de 34http://www.otierney.net/objective-c.html

int denominator;}

-(Fraction*) initWithNumerator: (int) n denominator: (int) d;-(void) setNumerator: (int) d;-(void) setDenominator: (int) d;-(void) setNumerator: (int) n andDenominator: (int) d;-(int) numerator;-(int) denominator;@end

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

-(void) setNumerator: (int) n { numerator = n;}

-(void) setDenominator: (int) d { denominator = d;}

-(void) setNumerator: (int) n andDenominator: (int) d { numerator = n; denominator = d;}

-(int) denominator { return denominator;}

-(int) numerator { return numerator;}

-(Fraction*) copyWithZone: (NSZone*) zone { return [[Fraction allocWithZone: zone] initWithNumerator: numerator denominator: denominator];}@end

Complex.h

#import <Foundation/NSObject.h>#import "Printing.h"

@interface Complex: NSObject <Printing> { double real; double imaginary;}

Page 24: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 24 de 34http://www.otierney.net/objective-c.html

-(Complex*) initWithReal: (double) r andImaginary: (double) i;-(void) setReal: (double) r;-(void) setImaginary: (double) i;-(void) setReal: (double) r andImaginary: (double) i;-(double) real;-(double) imaginary;@end

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

-(void) setReal: (double) r { real = r;}

-(void) setImaginary: (double) i { imaginary = i;}

-(void) setReal: (double) r andImaginary: (double) i { real = r; imaginary = i;}

-(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"

int main( int argc, const char *argv[] ) { // create a new instance Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10]; Complex *comp = [[Complex alloc] initWithReal: 5 andImaginary: 15]; id <Printing> printable; id <NSCopying, Printing> copyPrintable;

// print it printable = frac; printf( "The fraction is: " );

Page 25: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 25 de 34http://www.otierney.net/objective-c.html

[printable print]; printf( "\n" );

// print complex printable = comp; printf( "The complex number is: " ); [printable print]; printf( "\n" );

// this compiles because Fraction comforms to both Printing and NSCopyable copyPrintable = frac;

// this doesn't compile because Complex only conforms to Printing //copyPrintable = comp;

// 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

The fraction is: 3/10The complex number is: 5.000000 + 15.000000iFraction conforms to NSCopying

The protocol specification is quite simple. it is basically @protocol ProtocolName(methods you must implement) @end.To conform to a protocol, you put the protocols you're conforming to in <>'s, andcomma separate them. Example: @interface SomeClass <Protocol1, Protocol2,Protocol3>The methods that the protocol requires to be implemented are not required to be in thelist of methods for the header file. As you can see, Complex.h doesn't have adefinition for -(void) print, but it still implements it since it conforms to the protocol.One unique aspect of Objective-C's interface system is how you specify types. Ratherthan specifying it like Java or C++ as: Printing *someVar = ( Printing * ) frac; forexample, you use the id type with a restricted protocol: id <Printing> var = frac; Thisallows you to dynamically specify a type that requires multiple protocols, all with onevariable. Such as: id <Printing, NSCopying> var = frac;Much like using @selector for testing an object's inheritance, you can use @protocolto test for conformance of interfaces. [object conformsToProtocol: @protocol(SomeProtocol )] returns a BOOL if the object conforms to that protocol. This worksthe same for classes as well: [SomeClass conformsToProtocol: @protocol(SomeProtocol )].

Memory Management

Page 26: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 26 de 34http://www.otierney.net/objective-c.html

Up until now I've kind of dodged memory management in Objective-C. Sure you can calldealloc on an object, but what happens if the object contains pointers to other objects? Onehas to be concerned about freeing the memory of those objects as well. Also how does theFoundation framework manage memory when you create classes from it? This will all beexplained.Note: everything up until this point has been properly memory managed, incase you'rewondering.

Retain and ReleaseRetain and release are two methods inherited from any object that has NSObject as aparent. Each object has an internal counter that can be used to keep track of thenumber references an object has. So if you have 3 referneces, you don't want todealloc yourself. However once you reach 0, you should dealloc yourself. [objectretain] increments the counter by 1 (which starts at 1) and [object release] decrementsit by 1. If the [object release] invocation causes the count to reach 0, dealloc is thencalled.Fraction.m

...-(void) dealloc { printf( "Deallocing fraction\n" ); [super dealloc];}...

Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionmain.m

#import "Fraction.h"#import <stdio.h>

int main( int argc, const char *argv[] ) { Fraction *frac1 = [[Fraction alloc] init]; Fraction *frac2 = [[Fraction alloc] init];

// print current counts printf( "Fraction 1 retain count: %i\n", [frac1 retainCount] ); printf( "Fraction 2 retain count: %i\n", [frac2 retainCount] );

// increment them [frac1 retain]; // 2 [frac1 retain]; // 3 [frac2 retain]; // 2

// print current counts printf( "Fraction 1 retain count: %i\n", [frac1 retainCount] ); printf( "Fraction 2 retain count: %i\n", [frac2 retainCount] );

// decrement [frac1 release]; // 2 [frac2 release]; // 1

// print current counts printf( "Fraction 1 retain count: %i\n", [frac1 retainCount] ); printf( "Fraction 2 retain count: %i\n", [frac2 retainCount] ); // release them until they dealloc themselves [frac1 release]; // 1 [frac1 release]; // 0 [frac2 release]; // 0

Page 27: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 27 de 34http://www.otierney.net/objective-c.html

}

output

Fraction 1 retain count: 1Fraction 2 retain count: 1Fraction 1 retain count: 3Fraction 2 retain count: 2Fraction 1 retain count: 2Fraction 2 retain count: 1Deallocing fractionDeallocing fraction

The retain calls increment the counter. The release calls decrement it. One can get thecount as an int by calling [obj retainCount]. Once the retainCount reaches 0, bothobjects dealloc themselves and you can see this when both print out "Deallocingfraction."

DeallocWhen your object contains other objects, you must free them whenever you yourselfdealloc. One of the nice advantages to Objective-C is you can pass messages to nil, sothere isn't a lot of error checking to release an object.Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionAddressCard.h

#import <Foundation/NSObject.h>#import <Foundation/NSString.h>

@interface AddressCard: NSObject { NSString *first; NSString *last; NSString *email;}

-(AddressCard*) initWithFirst: (NSString*) f last: (NSString*) l email: (NSString*) e;-(NSString*) first;-(NSString*) last;-(NSString*) email;-(void) setFirst: (NSString*) f;-(void) setLast: (NSString*) l;-(void) setEmail: (NSString*) e;-(void) setFirst: (NSString*) f last: (NSString*) l email: (NSString*) e;-(void) setFirst: (NSString*) f last: (NSString*) l;-(void) print;@end

AddressCard.m

#import "AddressCard.h"#import <stdio.h>

@implementation AddressCard-(AddressCard*) initWithFirst: (NSString*) f last: (NSString*) l email: (NSString*) e { self = [super init];

Page 28: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 28 de 34http://www.otierney.net/objective-c.html

if ( self ) { [self setFirst: f last: l email: e]; }

return self;}

-(NSString*) first { return first;}

-(NSString*) last { return last;}

-(NSString*) email { return email;}

-(void) setFirst: (NSString*) f { [f retain]; [first release]; first = f;}

-(void) setLast: (NSString*) l { [l retain]; [last release]; last = l;}

-(void) setEmail: (NSString*) e { [e retain]; [email release]; email = e;}

-(void) setFirst: (NSString*) f last: (NSString*) l email: (NSString*) e { [self setFirst: f]; [self setLast: l]; [self setEmail: e];}

-(void) setFirst: (NSString*) f last: (NSString*) l { [self setFirst: f]; [self setLast: l];}

-(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

Page 29: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 29 de 34http://www.otierney.net/objective-c.html

#import "AddressCard.h"#import <Foundation/NSString.h>#import <stdio.h>

int main( int argc, const char *argv[] ) { NSString *first =[[NSString alloc] initWithCString: "Tom"]; NSString *last = [[NSString alloc] initWithCString: "Jones"]; NSString *email = [[NSString alloc] initWithCString: "[email protected]"]; AddressCard *tom = [[AddressCard alloc] initWithFirst: first last: last email: email];

// we're done with the strings, so we must dealloc them [first release]; [last release]; [email release];

// print to show the retain count printf( "Retain count: %i\n", [[tom first] retainCount] ); [tom print]; printf( "\n" ); // free memory [tom release];

return 0;}

output

Retain count: 1Tom Jones <[email protected]>

This example shows not only how to make a dealloc method, as shown inAddressCard.m, but one way to do member variables.The order of the 3 operations in each set method is very important. Lets say you'returnpassing a parameter of yourself to one of your methods (a bit of an odd example, butthis can happen). If you release first, THEN retain you will destruct yourself! That'swhy you should always 1) retain 2) release 3) set the value.Normally one wouldn't initialize variables with C strings because they don't supportunicode. The next example, with NSAutoreleasePool shows the proper way to dostrings and initializing.This is just one way of handling member variable memory management. One way tohandle this is to create copies inside your set methods.

Autorelease PoolWhen you want to start doing more programming using NSString and otherFoundation framework classes you need a more flexible system. This system is usingAutorelease pools.When developing Mac Cocoa applications, the auto release pool is setup automaticallyfor you.Based on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionmain.m

#import <Foundation/NSString.h>#import <Foundation/NSAutoreleasePool.h>#import <stdio.h>

int main( int argc, const char *argv[] ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

Page 30: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 30 de 34http://www.otierney.net/objective-c.html

NSString *str1 = @"constant string"; NSString *str2 = [NSString stringWithString: @"string managed by the pool"]; NSString *str3 = [[NSString alloc] initWithString: @"self managed string"];

// print the strings printf( "%s retain count: %x\n", [str1 cString], [str1 retainCount] ); printf( "%s retain count: %x\n", [str2 cString], [str2 retainCount] ); printf( "%s retain count: %x\n", [str3 cString], [str3 retainCount] );

// free memory [str3 release];

// free pool [pool release]; return 0;}

output

constant string retain count: ffffffffstring managed by the pool retain count: 1self managed string retain count: 1

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. Thereason is the first constant string is added to the autorelease pool automatically. Theother string is made using stringWithString. This method creates a string that is ownedby NSString class, which also puts it in the auto release pool.It's important to remember, for proper memory management, that convience methodslike [NSString stringWithString: @"String"] use autorelease pools, but alloc methodslike [[NSString alloc] initWithString: @"String"] do not use autorelease pools formanaging 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 thisBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionFraction.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>

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

Page 31: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 31 de 34http://www.otierney.net/objective-c.html

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Fraction *frac1 = [Fraction fractionWithNumerator: 2 denominator: 5]; Fraction *frac2 = [Fraction fractionWithNumerator: 1 denominator: 3];

// print frac 1 printf( "Fraction 1: " ); [frac1 print]; printf( "\n" );

// print frac 2 printf( "Fraction 2: " ); [frac2 print]; printf( "\n" );

// this causes a segmentation fault //[frac1 release];

// release the pool and all objects in it [pool release]; return 0;}

output

Fraction 1: 2/5Fraction 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 onthe object.The reason this works is because: for every retain, one release or autorelease must becalled. 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 autoreleasecalls on all objects and decrements them with [obj release] with the same number oftimes autorelease was called per object.As the comment says, uncommenting that line causes a segment fault. Sinceautorelease was already called on the object, calling release on it, and then releasingthe autorelease pool would attempt to call dealloc on an object that is nil, which is notvalid. 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 oftemporary objects, then release the pool. As you may wonder, it this means it ispossible to have more than one auto release pool at a time.

Foundation framework classesThe Foundation framework is similar to C++'s Standard Template Library. Although sinceObjective-C has real dynamic types, the horrible cludge that is C++'s templating is notnecessary. This framework contains collections, networking, threading, and much more.

NSArrayBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionmain.m

#import <Foundation/NSArray.h>#import <Foundation/NSString.h>#import <Foundation/NSAutoreleasePool.h>

Page 32: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 32 de 34http://www.otierney.net/objective-c.html

#import <Foundation/NSEnumerator.h>#import <stdio.h>

void print( NSArray *array ) { NSEnumerator *enumerator = [array objectEnumerator]; id obj;

while ( obj = [enumerator nextObject] ) { printf( "%s\n", [[obj description] cString] ); }}

int main( int argc, const char *argv[] ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSArray *arr = [[NSArray alloc] initWithObjects: @"Me", @"Myself", @"I", nil]; NSMutableArray *mutable = [[NSMutableArray alloc] init];

// enumerate over items printf( "----static array\n" ); print( arr );

// add stuff [mutable addObject: @"One"]; [mutable addObject: @"Two"]; [mutable addObjectsFromArray: arr]; [mutable addObject: @"Three"];

// print em printf( "----mutable array\n" ); print( mutable );

// sort then print printf( "----sorted mutable array\n" ); [mutable sortUsingSelector: @selector( caseInsensitiveCompare: )]; print( mutable ); // free memory [arr release]; [mutable release]; [pool release];

return 0;}

output

----static arrayMeMyselfI----mutable arrayOneTwoMeMyselfIThree----sorted mutable arrayIMeMyselfOneThreeTwo

There are two kinds of arrays (and of usually most data oriented Foundation classes)

Page 33: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 33 de 34http://www.otierney.net/objective-c.html

NSArray and NSMutableArray. As the name suggests, Mutable is changable, NSArraythen is not. This means you can make an NSArray but once you have you can't changethe length.You initialize an array via the constructor using Obj, Obj, Obj, ..., nil. The nil is anending delimiter.The sorting shows how to sort an object using a selector. The selector tells the array tosort using NSString's case insensitive compare. If your object has several sortmethods, you can choose anyone you want using this selector.In the print method, I used the method description. This is similar to Java's toString. Itreturns an NSString representation of an object.NSEnumerator is similar to Java's enumerator system. The reason why while ( obj =[array objectEnumerator] ) works is because objectEnumerator returns nil on the lastobject. Since in C nil is usually 0, this is the same as false. ( ( obj = [arrayobjectEnumerator] ) != nil ) might be preferable

NSDictionaryBased on an example in "Programming in Objective-C," Copyright © 2004 by SamsPublishing. Used with permissionmain.m

#import <Foundation/NSString.h>#import <Foundation/NSAutoreleasePool.h>#import <Foundation/NSDictionary.h>#import <Foundation/NSEnumerator.h>#import <Foundation/Foundation.h<#import <stdio.h>

void print( NSDictionary *map ) { NSEnumerator *enumerator = [map keyEnumerator]; id key;

while ( key = [enumerator nextObject] ) { printf( "%s => %s\n", [[key description] cString], [[[map objectForKey: key] description] cString] ); }}

int main( int argc, const char *argv[] ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys: @"one", [NSNumber numberWithInt: 1], @"two", [NSNumber numberWithInt: 2], @"three", [NSNumber numberWithInt: 3], nil]; NSMutableDictionary *mutable = [[NSMutableDictionary alloc] init];

// print dictionary printf( "----static dictionary\n" ); print( dictionary );

// add objects [mutable setObject: @"Tom" forKey: @"[email protected]"]; [mutable setObject: @"Bob" forKey: @"[email protected]" ];

// print mutable dictionary printf( "----mutable dictionary\n" ); print( mutable );

// free memory [dictionary release]; [mutable release];

Page 34: Objective c beginner's guide

24/11/10 21:11Objective-C Beginner's Guide

Página 34 de 34http://www.otierney.net/objective-c.html

[pool release];

return 0;}

output

----static dictionary1 => one2 => two3 => three----mutable [email protected] => [email protected] => Tom

Pros and ConsPros

CateogiesPosingDynamic typingPointer countingFlexible message passingNot an overly complex extention to CCan interface with C++ via Objective-C++

ConsNo namespacesNo operator overloading (this is often considered a Pro though, but operatoroverloading used properly can reduce code clutter)Still some cruft in language, although no more than C++

More InformationProgramming in Objective-C 2.0 (2nd Edition)Programming in Objective-CLearning Cocoa with Objective-CCocoa Programming for Mac OS XObject-Oriented Programming and the Objective-C LanguageGNUstep mini tutorials

Last modified: April 13, 2004.