In C, C++, Objective-C and some other programming languages pointers are values which contains an address that refers to another value in memory. In the aforementioned languages pointers usually appear in a syntax similar to:

int*values;// Pointer to an integer typeNSString*string;// Pointer to an NSString object

Pointers are generally constructed with malloc and destructed with free:

Because Multi-OS Engine has bindings for almost the complete C and Objective-C APIs in the iOS SDK, using pointers is inevitable. NatJ supports pointer usage and has the following pre-defined pointer types:

These are the most commonly used pointers. Memory to the pointed area is managed by Java’s GC.

Let’s look at the following problem: we want to create an NSIndexPath by using its init method which uses an NSUInteger pointer as its first argument:

// Create a NUIntPtr object with an allocated memory size of one NSUIntegerNUIntPtrptr=PtrFactory.newNUIntReference();// Set the referenced memory's value to 10ptr.set(10L);// Create the NSIndexPath objectNSIndexPathpath=NSIndexPath.indexPathWithIndexesLength(ptr,1);System.out.println("Path is "+path);

This code should output Pathis<NSIndexPath:0x7c234280>{length=1,path=10}

Another way to do this is by using another factory method, which uses the initial value as argument:

// Create a NUIntPtr object with an allocated memory size of one NSUInteger// and the referenced memory's value to 10NUIntPtrptr=PtrFactory.newNUIntReference(10L);// Create the NSIndexPath objectNSIndexPathpath=NSIndexPath.indexPathWithIndexesLength(ptr,1);System.out.println("Path is "+path.description());

This should have the same result Pathis<NSIndexPath:0x7c234370>{length=1,path=10}

This was good for a small introduction, but let’s look at a more likely situation, that is when there are more than one elements:

// Create a NUIntPtr object with an allocated memory size of 3 NSUIntegersNUIntPtrptr=PtrFactory.newNUIntArray(3);// Set the referenced memory's valueptr.set(10L);ptr.set(1,20L);// Create the NSIndexPath objectNSIndexPathpath=NSIndexPath.indexPathWithIndexesLength(ptr,3);System.out.println("Path is "+path);

This code should output Pathis<NSIndexPath:0x7c081d10>{length=3,path=10-20-0}

Note

Allocated memory returned from PtrFactory is zero’d out. This is why the third element in the path above is zero.

As this was a more life-like scenario, for a Java programmer this is very uncomfortable, this is why we support the following solution as well:

// Create a NUIntPtr object with an allocated memory size of 2 NSUIntegers// and set the referenced memory's valueNUIntPtrptr=PtrFactory.newNUIntArray(newlong[]{10L,20L});// Create the NSIndexPath objectNSIndexPathpath=NSIndexPath.indexPathWithIndexesLength(ptr,2);System.out.println("Path is "+path);

Output looks like this Pathis<NSIndexPath:0x7c08af40>{length=2,path=10-20}

While the creation of this pointer was simpler, the results were not exactly the same. In the previous example the referenced memory size was 3 NSUIntegers while in this one it was only 2 NSUIntegers.

The achieve the exact results we can use the copyFrom method:

// Create a NUIntPtr object with an allocated memory size of 3 NSUIntegersNUIntPtrptr=PtrFactory.newNUIntArray(3);// Set the referenced memory's valueptr.copyFrom(newlong[]{10L,20L});// Create the NSIndexPath objectNSIndexPathpath=NSIndexPath.indexPathWithIndexesLength(ptr,3);System.out.println("Path is "+path);

Guarded pointers add some safety to pointers (on the Java side). Accessing Non-guarded pointers are a bit faster, but those require much more attention at indexing, because indexing outside the memory’s bounds will not throw an exception rather the application will most likely crash due to a segmentation fault.
Guarded pointers however will do an index check and will throw an IndexOutOfBoundsException when needed.

Here’s a simple example where the guard saved us:

// Create a ShortPtr object with an allocated memory size of 5 shortsShortPtrptr=PtrFactory.newGuardedShortArray(5);try{// Index outside of the allocated memoryptr.set(5,(short)100);}catch(IndexOutOfBoundsExceptionex){System.out.println("Index was out of bounds!");}

The output is Indexwasoutofbounds! instead of an embarrassing application crash.

Guarded pointers can be created from Non-guarded pointers via the getGuarded method, but NatJ relies on the programmer to specify the bounds correctly.

Weak pointers differ from strong pointers in only one way, memory management is completely manual. This is useful when doing optimizations, for example:

// Create a CharPtr object with an allocated memory size of 5 chars// and set the referenced memory's value to 'Hello'CharPtrptr=PtrFactory.newWeakCharArray("Hello".toCharArray());// Create an NSString object from the pointer and make NSString responsible// for deallocation the pointerNSStringstring=NSString.alloc().initWithCharactersNoCopyLengthFreeWhenDone(ptr,5,true);System.out.println("My value is "+string);

The code should print MyvalueisHello

In this scenario this was useful because we didn’t copy the entire string when the NSString was initialized, rather we simply passed the pointer to it. When working with large amounts of data this could save a lot of time and memory!

Retrieving values can be done in multiple ways, of which the simplest are the get and toArray method variants.

Here is a simple example:

// Create a green UIColorUIColorcolor=UIColor.greenColor();// Create a pointer where the hue value will be storedNFloatPtrhue=PtrFactory.newNFloatReference();// Retrieve the hue valuecolor.getHueSaturationBrightnessAlpha(hue,null,null,null);System.out.println("Hue of color is "+hue.get());

The code will print something like this Hueofcoloris0.3333333432674408

Offsetting pointers can be useful in various ways that we will not go into, but instead show how to actually do it. The most important thing to know is that offsetted pointers still point to the memory region of the original pointer!

Let’s look at the next example where we want to copy ‘Hello’ five times after each other. One solution to this would be using the correct copyFrom method which can specify the target offset. The other solution is using pointer offsets:

// Create a CharPtr object with an allocated memory size of 25 charsCharPtrptr=PtrFactory.newCharArray(25);// Set the offsetted memory's value 'Hello'for(intidx=0;idx<25;idx+=5){ptr.ofs(idx).copyFrom("Hello".toCharArray());}// Create an NSString object from the pointerNSStringstring=NSString.alloc().initWithCharactersLength(ptr,25);System.out.println("5 * 'Hello' = "+string);

The output is 5*'Hello'=HelloHelloHelloHelloHello

Because the offsetted pointer always points to the original memory region, this code is also valid:

// Create a CharPtr object with an allocated memory size of 25 charsCharPtrptr=PtrFactory.newCharArray(25);// Set the offsetted memory's value 'Hello' and re-offset the pointerCharPtrofs=ptr;for(intidx=0;idx<5;++idx){ofs.copyFrom("Hello".toCharArray());ofs=ofs.ofs(5);}// Create an NSString object from the pointerNSStringstring=NSString.alloc().initWithCharactersLength(ptr,25);System.out.println("5 * 'Hello' = "+string);

Again, the output will be 5*'Hello'=HelloHelloHelloHelloHello

Here’s an example of using pointer offsetting instead of four NFloatPtrs:

// Create a blue UIColorUIColorcolor=UIColor.blueColor();// Create a pointer where the 4 components of HSBA will be storedNFloatPtrcmps=PtrFactory.newNFloatArray(4);// Retrieve the HSBA valuescolor.getHueSaturationBrightnessAlpha(cmps,cmps.ofs(1),cmps.ofs(2),cmps.ofs(3));System.out.println("HSBA values are "+Arrays.asList(cmps.toArray(4)));

C structure pointers are bound a bit differently than other pointers because the interpretation of how the code should be bound relies on the context it is used in. It can be either a reference to a single structure or a pointer to multiple structures.

Warning

The binding code for some of these methods will be changed to better reflect the function of them!

In the next example we will show you how structure references work:

// Create a CGRect object representing {{0, 0}, {200, 100}}CGRectrect=newCGRect(CoreGraphics.CGPointZero(),newCGSize(200.0,100.0));// Create two more rects for the slice and remainderCGRectslice=newCGRect();CGRectremainder=newCGRect();// Divide the rectCoreGraphics.CGRectDivide(rect,slice,remainder,50.0,CGRectEdge.MinXEdge);System.out.println("Slice is "+UIKit.NSStringFromCGRect(slice));System.out.println("Remainder is "+UIKit.NSStringFromCGRect(remainder));

These pointers are often not too useful, but there are some very good exceptions. The iOS SDK usually does not use exceptions for error handling, rather it uses pointers to NSError objects. Here is an example for how error handling can be implemented with error information provided by NSError:

// Create a NSURL to a non-existent websiteNSURLurl=NSURL.URLWithString("https://www.invalid.url/nothinghere");// Create the NSError pointerPtr<NSError>error=PtrFactory.newObjectReference(NSError.class);// Try to create a NSString from the bad URLNSStringstring=NSString.stringWithContentsOfURLEncodingError(url,Enums.NSUTF8StringEncoding,error);// Handle errorif(string==null){System.out.println(error.get().localizedDescription());}

Output will be something like: Theoperationcouldn’tbecompleted.(Cocoaerror256.)