Several new features were added to the Apple LLVM Compiler 4.0 to allow the use of Objective-C Literals and object subscripts.
This means that it is now possible to use the following shorthands to create and access elements of an
1 2 3
During compilation the subscripted array access is converted to a call to the
objectAtIndexedSubscript: method. So the above
NSLog statement would be converted to the following before compilation.
1 2 3
This addition to the Objective-C language is useful and certainly will make some code less verbose and easier to read.
However, many languages (particularly scripting languages) allow the use of negative indexes. Negative indexes are counted from the end of the array rather than the beginning. This led me to wonder if you can use negative indexes with the new Objective-C syntax.
Unfortunately, a quick look at the method definition for
objectAtIndexedSubscript: shows that the index parameter is an
NSUInteger, an unsigned integer. Therefore, as implemented, the new subscript indexes must be positive.
So, is it possible to add functionality to
NSArray to allow the use of negative indexes? The answer is Yes. The Objective-C runtime allows us to add the functionality to make it possible.
In order to do this we need to create our own version of the
objectAtIndexedSubscript: method. The new method,
BLC_objectAtIndexedSubscript: will look like:
1 2 3 4 5 6 7
You will notice that the parameter is now an
NSInteger rather than the unsigned
NSUInteger used by the original method.
You may also have noticed what appears to be a recursive call in line 6. As things stand at the moment this is a recursive call but the next step is to perform a method swizzle.
Method swizzling involves swapping two implementations of a method, in our case
BLC_objectAtIndexedSubscript:. We perform the method swizzle using the
method_exchangeImplementations function of the Objective-C runtime, declared in the
objc/runtime.h header file.
The method swizzle is performed as follows:
1 2 3 4
Now that the method implementations have been swizzled that recursive call in
BLC_objectAtIndexedSubscript: has become a call to the original method. The original method implementation is now called using the
Once we have swapped the methods we are able to use negative indexes as follows:
1 2 3
The full implementation of the new method and the method swizzling is contained in a category on
NSArray. The full listing is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
As you can see the above implementation also contains a category on
NSMutableArray which swizzles a replacement method for
setObject:atIndexedSubscript: to allow negative indexes in array assignment.
There is no associated header file for this category as the category does not add any new public methods to the
NSMutableArray class). Simply compiling the above
.m file into a binary will add the functionality to the array classes.
This category is available as a Gist at: https://gist.github.com/4076357
WARNING: This functionality is a hack and relies on the
clang compiler converting array subscripts into the associated call to
objectAtIndexedSubscript: without checking the positiveness of the index.