Cover by Vandad Nahavandipoor

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

O'Reilly logo

1.13. Defining Functionality for Classes

Problem

You want to define some functionality for your classes and allow them to be reused later.

Solution

Create instance or class methods for your classes in order to create reusable blocks of code, or simply call a method in your program.

Discussion

Nearly every programming language creates procedures and functions to encapsulate specific functionality, especially functionality that the programmer uses over and over. Some languages consider “procedure” and “function” just terms for the same thing, while others make a distinction between them. A procedure is a block of code with a name and an optional set of parameters. It does not have a return value. In Objective-C, a procedure returns void to indicate it does not return a value. A function is similar but does have a return value. Here is a simple procedure (with an empty body) written in C:

void sendEmailTo(const char *paramTo,
                 const char *paramSubject,
                 const char *paramEmailMessage){

  /* send the email here ... */
}

This procedure is named sendEmailTo and has three parameters: paramTo, paramSubject, and paramEmailMessage. We can then call this procedure as follows:

sendEmailTo("somebody@somewhere.com",
            "My Subject",
            "Please read my email");

Turning this procedure into a function that returns a Boolean value, we will have code similar to this:

BOOL sendEmailTo(const char *paramTo,
                 const char *paramSubject,
                 const char *paramEmailMessage){

  /* send the email here ... */

  if (paramTo == nil ||
      paramSubject == nil ||
      paramEmailMessage == nil){
    /* One or some of the parameters are nil */
    NSLog(@"Nil parameter(s) is/are provided.");
    return NO;
  }

  return YES;
}

Calling this function is similar to calling the sendEmailTo procedure except that with a function, we can retrieve the return value, like so:

BOOL isSuccessful = sendEmailTo("somebody@somewhere.com",
                                "My Subject",
                                "Please read my email");

if (isSuccessful){
  /* Successfully sent the email */
} else {
  /* Failed to send the email. Perhaps we should display
   an error message to the user */
}

In Objective-C, each method is created for a class. Creating Objective-C methods is quite different from writing procedures and functions in a programming language such as C. Methods fall into two categories: instance or class. Instance methods are methods that can be called on an instance of the class (that is, on each object you create based on the class), whereas class methods get called on the class itself and do not require an instance of the class to be created by the programmer. To create a method in Objective-C, follow these steps in the .m file of your target class:

  1. Type if you want an instance method or + if you want a class method.

  2. Choose the return type of your method and enclose it within parentheses—for instance, (void) for no return value, (BOOL) for a Boolean value, (NSObject *) to return an instance of NSObject, and so on.

  3. Choose a name for your method. Start the name with a lowercase letter. It is common in Objective-C to start method names with a lowercase letter—for instance, sendEmailTo instead of SendEmailTo.

  4. If you do not want any parameters for your method, jump to step 9.

  5. Choose two names for your parameter. One name becomes a part of the method name and will be used from outside the method (this is optional for all parameters except the first). The other name will be used as a parameter name inside the method. There is an exception to this in which the first name of the first parameter of a method is part of the name of the method that you chose in step 3. For this first parameter, you must only choose a second name, which becomes the parameter name used inside the method itself.

  6. Once you are done choosing the name for your parameter, choose the data type of the method and enclose it within parentheses.

  7. Put a colon after your parameter’s first chosen name (if any), and put the parentheses that carry the data type of your method followed by the second name for your parameter.

  8. Repeat steps 5 through 7 for any other parameters that you might have.

  9. Insert an open curly brace ({) after the method name and parameter names (if you have parameters) and a closing curly brace (}) at the end.

Going back to the sendEmailTo procedure example that we saw earlier, let’s attempt to create the same procedure as a method in Objective-C:

- (BOOL) sendEmailTo:(NSString *)paramTo
         withSubject:(NSString *)paramSubject
     andEmailMessage:(NSString *)paramEmailMessage{

  /* Send the email and return an appropriate value */

  if ([paramTo length] == 0 ||
      [paramSubject length] == 0 ||
      [paramEmailMessage length] == 0){
    /* One or some of the parameters are empty */
    NSLog(@"Empty parameter(s) is/are provided.");
    return NO;
  }

  return YES;

}

This is an instance method (-) that returns a Boolean value (BOOL). The name of this method is sendEmailTo:withSubject:andEmailMessage: and it has three parameters. We can then call this method in this way:

[self sendEmailTo:@"someone@somewhere.com"
      withSubject:@"My Subject"
  andEmailMessage:@"Please read my email."];

As mentioned previously, the first name of every parameter (except the first) is optional. In other words, we can construct the sendEmailTo:withSubject:andEmailMessage: method in another way with a different name:

- (BOOL) sendEmailTo:(NSString *)paramTo
                    :(NSString *)paramSubject
                    :(NSString *)paramEmailMessage{

  /* Send the email and return an appropriate value */

  if (paramTo length] == 0 ||
      [paramSubject length] == 0 ||
      [paramEmailMessage length] == 0){
    NSLog(@"Empty parameter(s) is/are provided.");
    return NO;
  }

  return YES;

}

Warning

I heavily discourage you from writing methods that have no external names for their parameters. This is indeed a very bad programming practice and will confuse you and those who you work with in the same team, regardless of how well you might have documented your code.

We can call this method like so:

[self sendEmailTo:@"someone@somewhere.com"
                 :@"My Subject"
                 :@"Please read my email."];

As you can see, the first implementation is easier to understand when you look at the invocation, since you can see the name of each parameter in the call itself.

Declaring and implementing a class method is similar to declaring and implementing an instance method. Here are a couple of things you have to keep in mind when declaring and implementing a class method:

  • The method type identifier of a class method is + instead of the - type identifier for instance methods.

  • You can access self in a class method.

  • Class methods are useful when you want to provide new methods of instantiation for your classes. For example, a class method named allocAndInit could both allocate and initialize an object and return the object to its caller.

Suppose we want to create a class named MyClass. In this class, we want to implement a class method named allocAndInit that will allocate and initialize an instance of MyClass and return the result to the caller. The header file of this class will look like this:

#import <Foundation/Foundation.h>

@interface MyClass : NSObject

+ (id) allocAndInit;

@end

The implementation of this class method will be very straightforward. A simple allocation followed by an initialization:

#import "MyClass.h"

@implementation MyClass

+ (id) allocAndInit{
  MyClass *result = [[MyClass alloc] init];
  return result;
}

@end

In our app delegate now we can use this class method to allocate and initialize an instance of MyClass, like so:

#import "AppDelegate.h"
#import "MyClass.h"

@implementation AppDelegate

@synthesize window = _window;

- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

  MyClass *instance1 = [MyClass allocAndInit];
  NSLog(@"Instance 1 = %@", instance1);

  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  return YES;
}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required