Chapter Nine: How To Create Your Own Classes

Matthew Campbell, November 27, 2011

At some point you will want to define your own classes to use in your app. So now let’s expand on the notion of object oriented programming by showing you how to implement your own custom classes. At this point you should be familiar with using existing objects in code; but you also need to be able to create your own types of objects.

Sub-Classes

One of the most common things that you will be doing with classes is something called sub-classing. As you can guess the iPhone has classes already in place to do things like present data tables, present windows and so on. Usually you will be creating your own object that inherits one of these preexisting objects and adding your own custom code to it. This is sub-classing.

Adding a New Class

XCode will help you do the initial set up work when you are creating a new class. To add a class you can simply control-click on a group folder in XCode and select New File… . In the dialog box that pops up select iOS > Cocoa Touch > Objective-C class and click Next . Then name your class and choose NSObject as the subclass.

Let’s do this now and call our class myClass. XCode created both the interface and the implementation files for myClass and added the code we need to get started. The interface file is the one that ends in .h. If you open that file you will see the code that XCode automatically filled in for us.

#import <Foundation/Foundation.h>

@interface myClass : NSObject{

}

@end

Interface File

This interface file uses an import directive to import the Foundation classes (which we always need to use). It also uses the interface keyword with the name of the class (myClass here) to indicate that we are defining a class.

The colon and the name NSObject means that our class will be a subclass of NSObject. Sub-classing and inheritance mean the same thing. You can say that myClass inherits from NSObject or you can say myClass is a subclass of NSObject.

We end the interface declaration with the end keyword @end.

Implementation File

XCode also created an implementation file, in case you did not notice XCode will create a separate file for the interface (header file that ends in .h) and the implementation file (ends in .m). Click on the implementation file to see the code that XCode added on our behalf.

#import "myClass.h"

@implementation myClass

@end

Our implementation file simply imports the myClass interface and includes the @implementation and @end keywords along with the name of our class.

Simple enough – we have created our first class. Right now it behaves exactly like NSObject, but soon we will be adding our own properties and methods to the class.

Adding Properties

When you add a property in a class you end up using a little black magic. That is, the system takes care of some of the implementation details for you if you do things in the typical way. You need to do two things to get a working property into your class: declare the property and then use @synthesize.

Here is what this looks like in the code:

Interface File (myClass.h):
#import <Foundation/Foundation.h>

@interface myClass : NSObject

@property (strong) NSString *name;

@end

The property is defined by using the @property directive. The key thing to note here is strong.

Back in the implementation file we use @synthesize to evoke all the black magic that is required to create the property based on our definition in the interface file.

#import "myClass.h"

@implementation myClass
@synthesize name;

@end

One thing that is significant though is that when you use primitive types as properties the syntax is a little different. For example, I am going to add a number property to my class that is an integer. Notice that it is done in a slightly different way:

#import <Foundation/Foundation.h>

@interface myClass : NSObject

@property (strong) NSString *name;
@property (assign) int number;

@end

The first thing is that there is no asterisk * since this is not an object variable. The other thing is that instead of using the strong keyword it is using assign in the property declaration.

Dot Notation

What all this does for you is give you the ability to assign and retrieve the property values using dot notation. You have already encountered this in the examples. Here is how you use dot notation with a myClass object.

//Instantiate an object from myClass:
myClass *object = [[myClass alloc] init];

//assign properties:
object.name = @"Obie";
object.number = 3;

//Access and use the properties
//with dot notation:
NSLog(@"My object's name is %@", object.name);
NSLog(@"My Object's number is %i", object.number);

Note that we use an alloc and init message even though we never created these in our class definition. Since our class is a subclass of NSObject we can simply use the original NSObject constructer to create objects. We can also code additional constructors if we want to set properties before we return our object to the system.

Class Methods

As you remember from chapter ten , objects have both properties and methods. Properties describe the object (the object’s attributes) while methods are what the object does (the object’s behaviors).

Furthermore, methods can be either class methods or instance methods. Class methods do not require an instance of a class (an object) to be used, you simply send the message to the class itself.

Here is how to declare a class method:

Interface File:

#import <Foundation/Foundation.h>

@interface myClass : NSObject

@property (strong) NSString *name;
@property (assign) int number;

+(void)writeSomething;

@end

Implementation File:

#import "myClass.h"

@implementation myClass

@synthesize name, number;

+(void)writeSomething{
	NSLog(@"I'm writing something");
}

@end

Here, the plus sign indicates that this is a class method and the void in between the parenthesis means that the method will not return a value. This is followed by the name of the method and curly braces. Whatever we want the function to do we put in between the curly braces as code.

Since this is a class method we do not even need an object to use this method. All we need to do is send a message to the class name itself:

[myClass writeSomething];

Instance Methods

Instance methods also are used to code behavior, but these are different than class methods because they may only be used by sending a message to an object. You code them the same way inside the class definition but you prefix the method with a minus sign instead of a plus sign:

Interface File:

#import <Foundation/Foundation.h>

@interface myClass : NSObject

@property (strong) NSString *name;
@property (assign) int number;

+(void)writeSomething;
-(void)writeSomethingForAnObject;

@end

Implementation File:

#import "myClass.h"

@implementation myClass

@synthesize name, number;

+(void)writeSomething{
	NSLog(@"I'm writing something");
}

-(void)writeSomethingForAnObject{
	NSLog(@"I'm writing something, but only as an object");
}

@end

To use an instance method we must have an object available.

myClass *object = [[myClass alloc] init];
[object writeSomethingForAnObject];

Method Parameters

Like functions in C you can pass parameters to methods in Objective-C. The syntax looks different. To put a parameter into the method declaration you must add a colon after the method name and then declare the object type and name the parameter:

Interface File:

#import <Foundation/Foundation.h>

@interface myClass : NSObject

@property (strong) NSString *name;
@property (assign) int number;

+(void)writeSomething;
-(void)writeSomethingForAnObject;
-(void)aMethodWithThisParameter:(NSString *)param;

@end

Implementation File:

#import "myClass.h"

@implementation myClass

@synthesize name, number;

+(void)writeSomething{
	NSLog(@"I'm writing something");
}

-(void)writeSomethingForAnObject{
	NSLog(@"I'm writing something, but only as an object");
}

-(void)aMethodWithThisParameter:(NSString *)param{
	NSLog(@"%@", param);
}

@end

To use this method you would do this (this will be familiar to you):

myClass *object = [[myClass alloc] init];
[object aMethodWithThisParameter:@"Say What?"];

Multiple Parameters

You may have your methods take more than one parameter. Objective-C has a unique way of doing this where you may include a descriptive phrase in the method declaration.

Interface File:

#import <Foundation/Foundation.h>

@interface myClass : NSObject

@property (strong) NSString *name;
@property (assign) int number;

+(void)writeSomething;
-(void)writeSomethingForAnObject;
-(void)aMethodWithThisParameter:(NSString *)param;
-(void)aMethodWithThisParameter:(NSString *)param 
		   andThisParameter:(int)num;

@end

Implementation File:

#import "myClass.h"

@implementation myClass
@synthesize name, number;

+(void)writeSomething{
	NSLog(@"I'm writing something");
}

-(void)writeSomethingForAnObject{
	NSLog(@"I'm writing something, but only as an object");
}

-(void)aMethodWithThisParameter:(NSString *)param{
	NSLog(@"%@", param);
}

-(void)aMethodWithThisParameter:(NSString *)param
               andThisParameter:(int)num{
	NSLog(@"%@ + %i", param, num);
}

@end

The key difference between methods with one parameter and methods with two is that starting with the second parameter each gets its own descriptive text prefix. Above it is andThisParameter: which is in front of the parameter num.

Your probably already guessed that you send a message to an object using two parameters like this:

[object aMethodWithThisParameter:@"One" andThisParameter:2];

Constructors

We know that constructers are special methods that return an instance of an object back to the system. We are already using the constructer that we inherited from NSObject, init to instantiate an object from myClass. We can create a custom constructor if it is needed.

In general, we always prefix our constructor with init. This is a matter of convention. Let’s start by defining our constructor in the myClass implementation file:

#import 

@interface myClass : NSObject

@property (strong) NSString *name;
@property (assign) int number;

+(void)writeSomething;
-(void)writeSomethingForAnObject;
-(void)aMethodWithThisParameter:(NSString *)param;
-(void)aMethodWithThisParameter:(NSString *)param 
				andThisParameter:(int)num;
-(id)initWithName:(NSString *) aName;

@end

Instead of being declared as a void type as our previous methods our constructor will be declared as an id. id means that our method will be returning a value that not yet defined. Whenever you replace the void with another type you are saying that this method will be returning a value (like a function in C).

Our constructor will also be taking a parameter which we will use to assign a name to the object’s name property. Here is how we implement this constructor:

#import "myClass.h"

@implementation myClass
@synthesize name, number;

+(void)writeSomething{
	NSLog(@"I'm writing something");
}

-(void)writeSomethingForAnObject{
	NSLog(@"I'm writing something, but only as an object");
}

-(void)aMethodWithThisParameter:(NSString *)param{
	NSLog(@"%@", param);
}

-(void)aMethodWithThisParameter:(NSString *)param 
				andThisParameter:(int)num{
	NSLog(@"%@ + %i", param, num);
}

-(id)initWithName:(NSString *) aName{
	if (self = [super init]){
		self.name = aName;
	}
	return self;
}

@end

In the if-then statement above we assign the object returned from the constructor that we inherited from NSObject to the current object (notice that there is only one equals sign). The self keyword always refers to the object in which the self keyword was placed while the super keyword refers to the class it is being inherited from (sometimes called the superclass).

Once we have successfully retrieved the object from the super init we can assign values to our properties.

Here is how you would use your new constructor to create an object:

myClass *object = [[myClass alloc] initWithName:@"MyObject"];

Hands On Time

Practice creating your class by first thinking all some attributes and behaviors could represent a person in your code. Keep it simple but meaningful. Use the techniques that you learned in this chapter to create a class definition for a person. Instantiate and use objects created from this class definition. Try using a NSMutableArray to hold a list of your person objects.