Difference between revisions of "An Overview of Objective-C Functions"
(New page: Functions are a vital part of writing well structured and efficient code. Objective-C functions provide a way to organize programs and avoid code repetition. In this chapter of [[Objective...) |
(No difference)
|
Revision as of 19:42, 20 October 2009
Functions are a vital part of writing well structured and efficient code. Objective-C functions provide a way to organize programs and avoid code repetition. In this chapter of Objective-C 2.0 Essentials we will look at how functions are declared and used.
What is a Function?
A function is a named block of code that can be called upon to perform a specific task. It can be provided data on which to perform the task and is capable of returning a result to the code that called it. For example, if a particular arithmetic calculation needs to be performed in an Objective-C program the code to perform the arithmetic can be placed in a function. The function can be programmed to accept the values on which the arithmetic is to be performed (referred to as arguments) and to return the result of the calculation. At any point in the program code where the calculation is required, the function is simply called and the result returned.
How to Declare an Objective-C Function
An Objective-C function is declared using the following syntax:
<return type> <function name> (<arg1 type> <arg1 name>, <arg2 type> <arg2 name>, ... )
{
// Function code
}
Explanations of the various fields of the function declaration are as follows:
- <return type> - Specifies the data type of the result returned by the function. If the function does not return a result then void should be specified. unless otherwise specified, functions are assumed to return an int.
- <function name> - The name assigned to function. This is the name by which the function will be referenced when it is called from with the application code. Note that, unless otherwise specified using the static specifier, function names are global and must be unique within the context of an application to avoid compilation errors.
- <argn type> - The type of the argument passed through to the function.
- <argn name> - The name by which the argument is to be referenced in the function code.
- Function code - The code of the function that does the work.
As an example, the following function takes no arguments, returns no result and simply displays a message:
void sayhello () { NSLog (@"Hello"); }
The following sample function, on the other hand, takes two integer arguments and returns the result of a multiplication of those numbers:
int multiply (int x, int y) { return x * y; }
Calling an Objective-C Function
Function Prototypes
Where a function is declared in relation to where it is called from is a significant factor. In the same way that most cultures reads a page from top to bottom, a compiler reads an Objective-C source file from top to bottom. If the compiler comes across a call to a function before it has found the function declaration it has to make assumptions about the type of result that function returns. The default assumption is that the function will return an int. Having made this assumption, if when the compiler finally reaches the function declaration, an error will have to reported if it is found to return a data type other than an int. To see this in action, try compiling the following code:
#import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; float result; result = multiply( 10, 20 ); [pool drain]; return 0; } float multiply (int x, int y) { return x * y; }
When an attempt to compile the above code is made, the compilation will fail with the following message:
sample.m:18: error: conflicting types for 'multiply' sample.m:10: error: previous implicit declaration of 'multiply' was here
The compiler is complaining because it had assumed when the function was called at line 10 that it returned an int because up until that point it has not found a function declaration to tell it otherwise. Having made this assumption it then found the function declaration and discovered it actually returned a float, thereby causing a conflict.
There are two solutions to this problem. One is to always declare function before they are called:
#import <Foundation/Foundation.h> float multiply (int x, int y) { return x * y; } int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; float result; result = multiply( 10, 20 ); [pool drain]; return 0; }
This is a work around for simple cases but can quickly become unmanageable in larger application code bases with multiple files and functions calling other functions. A much better solution is to use a function prototype. This is a declaration that can be placed at the top of code files that pre-declares the return type and arguments of a function. For example, the function prototype for our multiply function is as follows:
float multiply (int x, int y);
The argument names in the function prototype are entirely optional and the same result can be achieved with just the argument types:
float multiply (int, int);
Note that the semi-colon (;) is mandatory.
We can now applying this concept to our earlier example:
#import <Foundation/Foundation.h> float multiply (int, int); int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; float result; result = multiply( 10, 20 ); [pool drain]; return 0; } float multiply (int x, int y) { return x * y; }
For functions that accept a variable number of arguments, the '...' directive can be used in the function prototype:
int addAll (int, ...);
Function Scope and the static Specifier
Objective-C functions are considered by default to be global in scope. This means that a function declared in one file in a program can be called from any other code file in the program. This means that function names must be unique. Two functions with the same name will cause an error when the code linked during the build process. To confine the scope of a function to the file in which it is declared, simply prefix the declaration with the static keyword:
static float multiply (int x, int y) { return x * y; }
Static Variables in Functions
In the normal course of program execution, any variables declared locally in a function are discarded when the function exits and execution returns to the location the call was made. For example, each time the displayit function is called in the following code, variable j is re-initialized to 0 each time the function is called:
#import <Foundation/Foundation.h> void displayit (int); int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int i; for (i=0; i<5; i++) { displayit( i ); } [pool drain]; return 0; } void displayit (int i) { static int y = 0; y += i; NSLog (@"y + i = %i", y); }
When executed we get the following output from the above code:
2009-10-20 15:39:12.306 t[10128:10b] y + i = 0 2009-10-20 15:39:12.308 t[10128:10b] y + i = 1 2009-10-20 15:39:12.308 t[10128:10b] y + i = 2 2009-10-20 15:39:12.309 t[10128:10b] y + i = 3 2009-10-20 15:39:12.309 t[10128:10b] y + i = 4
If we want the value assigned to j to be retained after the function has executed, we simply declare the variable as static:
static int y = 0;
Now, when the code is compiled and run, we get the following output because the value of j is not being reset to 0 each time the function is called:
2009-10-20 15:39:32.194 t[10136:10b] y + i = 0 2009-10-20 15:39:32.195 t[10136:10b] y + i = 1 2009-10-20 15:39:32.195 t[10136:10b] y + i = 3 2009-10-20 15:39:32.196 t[10136:10b] y + i = 6 2009-10-20 15:39:32.196 t[10136:10b] y + i = 10