Pointers in Objective-C

Objective-C supports pointers, allowing you to pass references to values and objects within your program.

We’ll show how pointers work in contrast to values with 2 functions: zeroval and zeroptr. zeroval has an NSInteger parameter, so arguments will be passed to it by value. zeroval will get a copy of ival distinct from the one in the calling function.

#import <Foundation/Foundation.h>

void zeroval(NSInteger ival) {
    ival = 0;
}

zeroptr in contrast has an NSInteger * parameter, meaning that it takes an NSInteger pointer. The *iptr code in the function body then dereferences the pointer from its memory address to the current value at that address. Assigning a value to a dereferenced pointer changes the value at the referenced address.

void zeroptr(NSInteger *iptr) {
    *iptr = 0;
}

Here’s the main function demonstrating the use of these functions:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 1;
        NSLog(@"initial: %ld", (long)i);
        
        zeroval(i);
        NSLog(@"zeroval: %ld", (long)i);
        
        // The &i syntax gives the memory address of i,
        // i.e. a pointer to i.
        zeroptr(&i);
        NSLog(@"zeroptr: %ld", (long)i);
        
        // Pointers can be printed too.
        NSLog(@"pointer: %p", &i);
    }
    return 0;
}

zeroval doesn’t change the i in main, but zeroptr does because it has a reference to the memory address for that variable.

To run this program, save it as pointers.m and compile it with:

$ clang -framework Foundation pointers.m -o pointers
$ ./pointers
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x7ffeefbff5d8

Note that in Objective-C, most objects are already handled by pointers. When you create an instance of an Objective-C class, you’re actually creating a pointer to that object. However, for primitive types like NSInteger, you need to explicitly use pointers if you want to pass by reference.