Changes

Jump to: navigation, search

Objective-C Variable Scope and Storage Class

7,323 bytes added, 15:01, 20 October 2009
Function Scope
Objective-C code is typically structured into a number of classes and code units called ''functions'' (for more details on functions see the chapter entitled [[An Overview of Objective-C Functions]]). In terms of variable scope, functions are really little more than statement blocks in that they are encapsulated in braces and variables declared within those braces are local to that block.
 
In the following example is intended to illustrate this concept and contains two functions named ''main()'' and ''multiply()'' respectively.
 
<pre>
#import <Foundation/Foundation.h>
 
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
 
int j = 10;
int k = 20;
int result;
 
result = mutliply();
 
[pool drain];
 
return 0;
}
 
int multiply()
{
return j * k;
}
</pre>
 
An attempt to compile the above code example will result in a compiler error similar to the following:
 
<pre>
In function 'multiply':
error: 'j' undeclared (first use in this function)
error: (Each undeclared identifier is reported only once
error: for each function it appears in.)
error: 'k' undeclared (first use in this function)
</pre>
 
The reason for this error is that variables ''j'' and ''k'' are declared in the ''main()'' function and are, therefore, local to that function. As such, these variables are not visible to the ''multiply()'' function resulting in an error when we try to reference them in that function. If we wanted to have access to the values of those variables we would have to pass them through as arguments to the multiply function (for details on function arguments refer to [[An Overview of Objective-C Functions]]).
 
As with block scope, it is possible to have multiple variables with the same inside a single function as long as each instance appears within its one local scope. For example, we can add a while loop to our ''main()'' that has its own local of variable also named ''j'':
 
<pre>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
 
int j = 10;
int k = 20;
int result;
 
while (k > 0)
{
int j = 0;
j =+ k;
k--;
}
 
[pool drain];
 
return 0;
}
</pre>
 
== Global Scope ==
 
A variable that has ''global scope'' is potentially accessible to code anywhere else in an Objective-C program, regardless of whether the code is in a separate file to the one in which the variable is declared. Global variables are declared ''outside'' of any statement blocks and are typically placed near the top of a source file.
 
The following is a code listing from an Objective-C source file named ''main.m'':
 
<pre>
#import <Foundation/Foundation.h>
 
int myVar = 321;
 
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
NSLog (@"myVar = %i", myVar);
[pool drain];
 
return 0;
}
</pre>
 
As we can see, the global variable ''myVar'' is declared outside of the ''main()'' function is is not embedded into a statement block or class declaration of any kind. Because this is a global variable, it is directly accessible inside the main function and would also be accessible from any other functions and statement blocks within the context of the ''main.m'' code file.
 
As previously stated, global variables are potentially accessible across all the source files that constitute an Objective-C program. The key word here is ''potentially'' and we say this because global access across multiple source files is not the default for a global variable. Take, for example, the following two code files. The first file, ''main.m'' contains the declaration of the global variable ''myVar'' and calls a function named ''displayit()'':
 
<pre>
#import <Foundation/Foundation.h>
 
int myVar = 321;
 
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
NSLog (@"myVar = %i", myVar);
 
displayit();
[pool drain];
 
return 0;
}
</pre>
 
The second file, named ''displayit.m'' contains the code for the ''displayit()'' function and displays the value currently assigned to the global ''myVar'' variable:
 
<pre>
void displayit()
{
NSLog (@"MyVar from different source file is %i", myVar);
}
</pre>
 
If we try to compile these two code files into an executable either using Xcode or from the command-line we will get an error that reads as follows:
 
<pre>
gcc -framework Foundation main.m displayit.m -o main
displayit.m: In function 'displayit':
displayit.m:3: error: 'myVar' undeclared (first use in this function)
displayit.m:3: error: (Each undeclared identifier is reported only once
displayit.m:3: error: for each function it appears in.)
</pre>
 
The reason for this is that although the variable was declared as global in ''main.m'' we still need to take one extra step in ''displayit.m'' to make the variable accessible in this file. This step involves declaring that the variable is ''external'' to the local file. This declaration is achieved using the ''extern'' keyword. For example, to make ''myVar'' accessible in ''displayit.m'' the following code would be required:
 
<pre>
extern int myVar;
 
void displayit()
{
NSLog (@"MyVar from different source file is %i", myVar);
}
</pre>
 
Having made this change, the code will now compile and run.
 
== File Scope ==
 
In the preceding section on ''global scope'' we talked about how a variable declared outside of any statement blocks is considered to be global and may be access both by code in the same file, or by code in different files. Suppose, however, that you wanted a variable to accessible ''only'' to code within the file where the variable is declared. This is achieved by using the ''static'' specifier when declaring the variable. For example, the following code is from a file named ''main.m''. This file declares variable ''myVar'' to be static. As such, the variable will be accessible only to code within the ''main.m'' file and cannot be accessed by code in any other file:
 
<pre>
#import <Foundation/Foundation.h>
 
static int myVar = 543;
 
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
NSLog (@"myVar = %i", myVar);
 
displayit();
[pool drain];
 
return 0;
}
</pre>
 
== Variable Storage Class ==
 
Variable storage class specifiers are used when declaring a variable to give the compiler information about how a variable is likely to be used and accessed within the program being compiled. So far in this chapter we have actually already looked at two storage class specifiers in the form of ''extern'' and ''static''. A full list of variable storage class specifiers is as follows:
 
* '''extern''' - Specifies that the variable name is referencing a global variable specified in a different source file to the current file.
 
* '''static''' - Specifies that the variable is to be accessible only within the scope of the current source file.
 
* '''auto''' - The default value for variable declarations. Specifies the variable is to be local or global depending on where the declaration is made within the code. Since this is the default setting this specifier is rarely, if ever, used.
 
* '''const''' - Declares a variable as being read-only. In other words, specifies that once the variable has been assigned a value, that value will not be subsequently changed.
 
* '''volatile''' - Specifies that the value assigned to a variable will be changed in subsequent code. The default behavior for variable declarations.

Navigation menu