|
|
Line 7: |
Line 7: |
| <hr> | | <hr> |
| | | |
− | <google>BUY_OBJC</google> | + | <htmlet>objc<htmlet> |
| | | |
| In the preceding chapters on object-oriented programming we have used, but not described, a feature of Objective-C (actually derived from the underlying C programming language) in the form of ''pointers'' and ''indirection''. A clear understanding of this topic is important when working with objects and also when passing values as arguments to methods and functions. | | In the preceding chapters on object-oriented programming we have used, but not described, a feature of Objective-C (actually derived from the underlying C programming language) in the form of ''pointers'' and ''indirection''. A clear understanding of this topic is important when working with objects and also when passing values as arguments to methods and functions. |
Revision as of 21:05, 1 February 2016
Cannot find HTML file objc<htmlet>
In the preceding chapters on object-oriented programming we have used, but not described, a feature of Objective-C (actually derived from the underlying C programming language) in the form of ''pointers'' and ''indirection''. A clear understanding of this topic is important when working with objects and also when passing values as arguments to methods and functions.
== How Variables are Stored ==
When we declare a variable in Objective-C and assign a value to it we are essentially allocating a location in memory where that value is stored. Take, for example, the following variable declaration:
<pre>
int myvar = 10;
<pre>
When the above code is executed, a block of memory large enough to hold an integer value is reserved in memory and the value of 10 is placed at that location. Whenever we reference this variable in code, we are actually using the variable value. For example, the following code adds the value of ''myvar'' (i.e. 10) to the constant value 20 to arrive at a result of 30.
<pre>
int result = 20 + myvar;
<pre>
Similarly, when we pass a variable through as an argument to a method or function we are actually passing the ''value'' of the variable, not the variable itself. To better understand this concept, consider the following sample program:
<pre>
#import <FoundationFoundation.h>
void myFunction(int i)
{
i = i + 10;
}
int main (int argc, const char * argv[])
{
@autoreleasepool {
int myvar = 10;
NSLog (@"Before call to function myvar = %i", myvar);
myFunction (myvar);
NSLog (@"After call to function myvar = %i", myvar);
}
return 0;
}
<pre>
The above program consists of a main function that declares our ''myvar'' variable and displays the current value. It then calls the function ''myFunction'' passing through the value of the ''myvar'' variable. The ''myFunction'' function adds 10 to the value it was passed as an argument and then returns to the main function where the value of ''myvar'' is once again displayed. When compiled and executed the following output is displayed:
<pre>
Before call to function myvar = 10
After call to function myvar = 10
<pre>
Clearly, even though the value passed through to ''myFunction'' was increased by 20 the value of ''myvar'' remained unchanged. This is because what was passed through as an argument to ''myFunction'' was the ''value'' of ''myvar'', not the ''myvar'' variable itself. Therefore, in ''myFunction'' we were simply working on a constant value of 10 that had absolutely no connection to the original ''myvar'' variable.
In order to be able to work on the actual variable in the function we need to use something called indirection.
== An Overview of Indirection ==
Indirection involves working with pointers to the location of variables and objects rather than the contents of those items. In other words, instead of working with the ''value'' stored in a variable, we work with a ''pointer'' to the ''memory address'' where the variable is located.
Pointers are declared by prefixing the name with an asterisk (*) character. For example to declare a pointer to our ''myvar'' variable we would write the following code:
<pre>
int myvar = 10;
int *myptr;
<pre>
In the above example we have declared our ''myvar'' variable and then declared a variable named ''myptr'' as being of type ''pointer to an integer''. Having declared both our variable and our pointer we now need to assign the ''address'' of our variable to the pointer. The address of a variable is referenced by prefixing it with the ampersand (&) character. We can, therefore, extend our example to assign the address of the ''myvar'' variable to the ''myptr'' variable:
<pre>
int myvar = 10;
int *myptr;
myptr = &myvar;
<pre>
We now have now implemented a level of indirection by creating a ''pointer'' to our variable. As such, we can now pass this pointer through as an argument to our function such that we will be able to work on the actual variable, rather than just the value (10) of the variable. In order to access the value of a variable using a pointer to that variable, we prefix the pointer variable name with an asterisk (*). When we do this we are telling the compiler we want to work with the contents of the variable or object at the memory address contained within the pointer:
<pre>
int myvar = 10;
int *myptr;
myptr = &myvar;
*myptr = *myptr + 15;
<pre>
Similarly, we can modify our function to accept a pointer to an integer and perform the addition on that variable. As such, we can now modify our previous program as follows:
<pre>
#import <FoundationFoundation.h>
void myFunction(int *i)
{
*i = *i + 10;
}
int main (int argc, const char * argv[])
{
@autoreleasepool {
int myvar = 10;
int *myptr;
myptr = &myvar;
NSLog (@"Before call to function myvar = %i", myvar);
myFunction (myptr);
NSLog (@"After call to function myvar = %i", myvar);
}
return 0;
}
<pre>
Now because we are passing through a pointer to ''myvar'' when we call the function and have modified the function to work with the contents of the variable, the output clearly indicates that the function changed the value of ''myvar'' when it was called. We have, therefore, just used indirection.
<pre>
Before call to function myvar = 10
After call to function myvar = 20
<pre>
== Indirection and Objects ==
So far in this chapter we have used indirection with a variable. The same concept applies for objects. In previous chapters we worked with our BankAccount class. When doing so we wrote statements similar to the following:
<pre>
BankAccount *account1;
BankAccount *account1 = [[BankAccount alloc] init];
<pre>
<htmlet>adsdaqbox_flow.html
The first line of code (BankAccount *account1;) is actually declaring that the variable named
account1 is a
pointer to an object of type BankAccount. We are, therefore, using indirection to provide a handle to our object. The calls to the alloc and init methods subsequently create the object in memory and the assign the address of that object to the account1 pointer variable. We are, therefore, using indirection once again.
One key point to note is that we do not need to prefix the object pointer with a * when perform operations such as calling methods. For example, we can call a method on our account1 object without using an asterisk:
[account1 displayAccountInfo];
Indirection and Object Copying
Due to the fact that references to objects utilize indirection it is important to understand that when we use the assignment operator (=) to assign one object to another we are not actually creating a copy of the object. Instead, we are creating a copy of the pointer to the object. Consider, therefore, the following code:
BankAccount *account1;
BankAccount *account2;
BankAccount *account1 = [[BankAccount alloc] init];
account2 = account1;
In the above example, we will end up with two pointers (account1 and account2) that point to the same location in memory. We have not, therefore, created a copy of account1. For details on copying objects refer to the chapter entitled Copying Objects in Objective-C.
<google>BUY_OBJC_BOTTOM</google>