Defining a Class

Sat, Aug 2

One of the first topics to cover when learning to develop native iPhone applications is how to code in Objective-C. Apple offers the Objective C Reference , a good resource, however, the best way to learn is by writing code. I took to Xcode to write a few simple examples, you’ll find the code below. At the end of this post I also include a link to download the Xcode project I was working with.

There are two aspects to a class, the interface and the implementation, both of which I recommend you store in separate files (although this is not a requirement).

The interface looks as follows:

1
2
3
4
5
6
7
@interface NameOfClass : NameOfSuperclass
{
  instance variables here...
}
class methods
instance methods
@end

The interface for my example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ===========================
// = Interface for SomeClass =
// ===========================
#import "SomeClass.h"
@interface SomeClass : NSObject
{
  NSString *str;
  NSDate *date;
  int x;
} 
 
// Getters
-(int) x;
-(NSString *) str;
-(NSDate *) date;
 
// Setters
-(void )setX:(int) input;
-(void) setStr:(NSString *)input;
-(void) setDate:(NSDate *)input;
 
// Other
-(void) printInstanceVars;
-(void) dealloc;
@end

A good coding practice is to save the implementation definition in a file with a name that matches the class name, with an extension of .h (for exampe: SomeClass.h).

This class is inherited from NSObject, the uber object. The class has three instance variables, two that point to other objects, one that references an integer variable. Take note of the getter methods: in Objective-C there is typically no ‘get’ in the front of the method name (in Java this might look like getX or getStr). Second, it should be obvious, that an instance variable can have the same name as a method, as it generally does with a getter. The ‘-’ in the front of the definition, signifies that the method is an instance method. We use a ‘+’ to define a class method (more on class methods in a future post).

One important thing to point out is the format used when declaring methods. For example, setStr() is defined as -(void)setStr: (NSString *) input ; This is translated to, the method setStr is an instance method (given the ‘-’) that returns a void type. The method takes one argument, that is a pointer to an NSString object, the name assigned to the parameter is ‘input’. The reason for the name will become more apparent when you see the implementation of the method below.

The format for the implementation of a class looks as follows:

1
2
3
4
5
6
7
@implementation NameOfClass : NameOfSuperclass
{
  instance variables here...
}
class methods
instance methods
@end

Here is how the implementation for the above class looks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#import "SomeClass.h"
#import <stdio.h>
// ================================
// = Implementation for SomeClass =
// ================================
 
@implementation SomeClass
// =================
// = Getter methods =
// =================
- (int) x
{
  return x;
}
 
- (NSString *) str
{
  return str;
}
 
- (NSDate *) date
{
  return date;
}
 
// =================
// = Setter Methods =
// =================
- (void) setX:(int)input
{
  x = input;
}
 
- (void) setStr:(NSString *)input
{
  [input retain];
  [str release];
  str = input;
}
 
- (void) setDate:(NSDate *)input
{
  [input retain];
  [date release];
  date = input;
}
 
// ================================
// = Print the instance vars =
// ================================
 
-(void) printInstanceVars
{
  // Use the getter method of the 'self' object to print object instance variables
//  NSLog(@&quot;\n x: %d\n str: %@\n date: %@\n&quot;, [self x], [self str], [self date]);
 
  // The class can directly access the instance variables (versus calling message as above)
  NSLog(@&quot;\n x: %d\n str: %@\n date: %@\n&quot;, x, str, date);
}
 
// ====================================
// = Dealloc all object instance vars =
// ====================================
 
-(void) dealloc
{
  // No release needed of the integer instance variable 'x'
  [str release];
  [date release];
  [super dealloc];
}
@end

Other than learning the syntax of Objective-C, if you are familiar with OO development, most of this should be pretty clear.
A couple of things to point out:

  • The preferred file name for the implementation is the class name with a .m extension, in this example: SomeClass.m
  • Notice how this file imports "SomeClass.h" to read the class definition. If you are familiar with C, this is analgous to the #include directive. The benefit of #import is that the compiler will do the work for you to verify that the include file is only read once. If you’ve done any amount of coding in C, you’ll appreciate this convenience, if not, you won’t understand how nice a feature this is.
  • Within an instance method, all instance variables are within scope. For example, notice how the getter and setter methods refer to the instance variables.
  • Notice in printInstanceVars() method that there are two means to access the instance variables. You can use the ‘self’ object an send a message to the getter method (more on objects and messages in the next post), or you can directly access the instance variables.
  • If instance variables are pointers to objects, as are ‘str’ and ‘date’, it’s your responsibility as the developer to free the memory for those objects. The dealloc method is where you do this work. More on that to come…

To complete the example, the code that follows declares an instance of the SomeClass object, and uses the setter/getter methods to print the instance variables to the console.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import <Foundation/Foundation.h>
#import "SomeClass.h"
int main(int argc, const char * argv[])
{
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  SomeClass *ptr = [[SomeClass alloc] init];
 
  [ptr setX:99];
  [ptr printInstanceVars];
 
  [ptr setStr:@&quot;Testing&quot;];
  [ptr printInstanceVars];
 
  [ptr setDate:[NSDate date]];
  [ptr printInstanceVars];
 
  [ptr release];
  [pool drain];
  return 0;
 
}

A few comments on the above code:

  • Notice this file imports the SomeClass.h interface file.
  • Like working with C, main() is the function that gets everything started.
  • ‘ptr’ is a reference to an object of the SomeClass class.
  • Calling instance methods of an object follows this form: [object message:parameters]

A screenshot of the output from within Xcode of this example is below:

Creating Classes

I recommend you download the Xcode project and give it a go.

Let’s go with that for today. In the next post I’ll talk further about this simple example, including instantiation of classes, sending messages to methods and freeing memory of the instance variables.

7 comments

Great article! I would also recommend that folks new to Objective-C (folks familiar with it, too!) take a look at 2 new features of Objective-C 2.0 introduced in 10.5/Leopard: properties and fast enumeration.

Using ObjC2 properties forgoes the need to write getter-setter methods entirely:

@interface SomeClass : NSObject
{
NSString *_str;
NSDate *_date;
int _x
}
@property(retain, readwrite) NSString *str;
@property(retain, readwrite) NSDate *date;
@property(assign, readwrite) int x;
:

@implementation SomeClass
@synthesize str = _str;
@synthesize date = _date;
@synthesize x = _x;

In this case the @property declaration, combined with the @synthesize, will automatically generate getter/setter methods for each instance variable — a real time-saver when your class declares a 20 variables (or even if you only declare 1). Since most getter/setter implementations follow the same code template, this can be a nice time saver and leaves the code less cluttered and easier to maintain.

Properties declared with (retain, …) will automatically call [NSObject retain] when a new value is assigned to the instance variable via the synthesized setter, as well as [NSObject release] for the previously assigned object. The “assign” modifier tells the compiler to generate a simple assignment, useful for non-Cocoa variable types, or NSObject references which do not need to be retained. Variables can alternately be declared “readonly”, which generates compiler errors if the code attempts to make an assignment. These are the most common modifiers — the Objective-C 2.0 guide defines others for special cases.

Concurrent with the new property declarations is the change to “.” notation for accessing getter/setting methods.

SomeClass *anInst = [[[SomeClass alloc] init] autorelease];
anInst.str = @”Hello, world!”; // retained
anInst.date = [NSDate date]; // retained
anInst.x = 5; // assigned

The underscore (“_”) notation in the instance variable declarations are optional, but a useful way to distinguish direct variable references from getter/setter references in your code.

@implementation SomeClass
:
- (void) setDefaultX
{
_x = 5; // direct assignment
}

Once you get used to the property syntax, the older form of Objective-C feels clunky.

Fast enumeration is a newer way to iterate through NSArray collections. The traditional way of writing iteration loops is familiar to most Cocoa programmers:

NSArray *aList = [myClass getListOfObjects];
NSEnumerator *anEnum = [aList objectEnumerator];
NSString *aStr = nil;
while (nil != (aStr = [anEnum nextObject])) {…}

With fast enumeration, the same code appears as follows:

NSArray *aList = [myClass getListOfObjects];
for (NSString *aStr in aList) {…}

Not only is it less code, which is always a good thing, but the fast enumeration form allows the compiler to make optimizations in the loop interation that can be several times faster than the older NSEnumerator-based loops.

I find these new features of Objective-C 2.0 to be very handy in writing more compact, readable code, which lets me concentrate more on the logic of my own application, rather than the syntactic overhead of writing classes.

Enjoy!

by stevebert on Aug 10, 2008. Reply #

good post man, thnks!

by bangsoul on Jul 16, 2011. Reply #

Thanks for posting, especially the comment by Brian. I am coming to Obj-C from .NET (mainly C#) and boy, I’m having the hardest time trying to get in tune with the new syntaxes.

I always use properties (getters and setters) in C# so this definitely helps me understand how to set them up in Obj-C. Same goes for the foreach loop in C# when looping through enumerated objects and seeing how it’s done in Obj-C.

I’m glad to see that Obj-C 2.0 has introduced simpler ways to set properties and iteration loops or I’d have given up. Well, probably not since I love the machine!

Keep ‘em coming!

by Chad W. Taylor on Aug 11, 2008. Reply #

Thanks for posting such an awesome article on objective C for intiators. I am from Java background, and currently shifted to Cocoa Objective C- Java Development in iPhone.

With this article I have realized that Programming in Objective-C is very much similar to Java except syntax if considering import of files, getter and setter methods and their return types.

I am trying to create a directory where I want to save the Mobile no and Name of the person and want to same it in the iPhone memry. For this I am using XCode IDE.

Can you please guide me, how can I save data in iPhone memory.

Waiting for your new article on saving data in iPhonr memory.

With regards,

Ankit Thakur

by Akit Thakur on Aug 16, 2008. Reply #

I am new to programming and I am learning Obj C. I am stuck on a tutorial where I keep getting an error saying that my getter “r” is undeclared even though I have declared it in the @interface section.

Perhaps someone is willing to take a look and tell me what I am doing wrong? Here is the @ interface section:

@interface TemperatureConvert : NSObject
{
int fahrenheit;
int celsius;
int result;

}
-(int) retrieveResult: (int) r;
-(void) setFahrenheit: (int) f;
-(void) setCelsius: (int) c;
-(void) print;

The voids all work fine… just the getter -(int) retrieveResult: (int) r; produces an error in the program section saying that r is not declared.

Any thoughts?

Greg

by Greg on Nov 27, 2009. Reply #

Hey Greg,

I assume you are closing the interface with an “@end” statement? I don’t get an error when compiling the above, you may have an error in the implementation file…

John

by John Muchow on Nov 27, 2009. Reply #

Thanks John, Yes -using @end. Above I was putting the conversion formula in the definition of (int) retrieveResult: (int)r; and asking it to return the result of the calculation.

I changed this approach and now it works by having a -(void) convertToCelsius; method and then a separate method that returns the value of the calculation. Here is the whole thing:

@interface TemperatureConvert : NSObject
{
  int fahrenheit;
  int celsius;
}
-(void) convertToCelsius;
-(void) setFahrenheit: (int) f;
-(float) celsius;
-(void) print;
 
@end
 
//--------@implementation section------
 
@implementation TemperatureConvert
-(void) print
{
  NSLog (@"%i degrees fahrenheit converted to celsius is %i degrees celsius", fahrenheit, celsius);
}
 
-(void) setFahrenheit: (int) f
{
  fahrenheit = f;
}
 
-(int) fahrenheit
{
  return fahrenheit;
}
 
-(void) convertToCelsius
{
  celsius =(fahrenheit - 32) /1.8;
}
 
-(float) celsius
{
  return celsius;
}
 
@end
 
//--------@programsection--------
 
int main (int argc, const char * argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
  //create an instance of a TempConvert
  TemperatureConvert *myTemperatureConvert = [[TemperatureConvert alloc] init];
 
  //set Fahrenheit to 27 degrees
  [myTemperatureConvert setFahrenheit: 101];
 
  //calculate conversion to celsius 
  [myTemperatureConvert convertToCelsius];
 
  //display result of conversion
  NSLog(@"%i degrees fahrenheit converted to celsius is %i degrees celsius",[myTemperatureConvert fahrenheit],[myTemperatureConvert celsius]);
 
  [myTemperatureConvert print];
  [myTemperatureConvert release];
 
    [pool drain];
    return 0;
}

by Greg on Nov 30, 2009. Reply #

Leave a Comment