Hi Oliver,
I just stumbled upon this question and thought I'd answer it, though I hope you have worked it out since and haven't been stuck on this for 6 months ;)
Firstly, assuming that stringLength == [string length]
then you need to check that the index is strictly less than stringLength, not less that or equal, ie:
for (i=0; i < stringLength; i++) {
unichar currentCharacter = [string characterAtIndex:i];
...}
As an example, a 5 character string has 5 valid indexes; 0, 1, 2, 3 and 4.
That fix should stop you from getting an exception, but here is some more explanation of exceptions (which I wrote before noticing your off-by-one error in the index):
Exceptions aren't like normal return values, they are like a special emergency channel by which a function can inform its caller of an error condition, without having to jam an error condition into its normal return value.
The terminology is that Exceptions aren't "returned" so much as they are "raised" or "thrown" (depending on the language). An exception is then "caught" or "rescued from" (depending on the language).
Exceptions should only be used in exceptional circumstances, and if there is some way of avoiding an exception (by sanitising input) you should do that first. Another reason to avoid exceptions when possible is that in some languages the process of catching exceptions is not terribly efficient, and can also leave memory allocation a little bit up-in-the air.
But in exceptional circumstances, they are useful way of signalling an error to a calling function without having to contrive some way of expressing the error condition in your range of return values.
So, on to the practicalities. The syntax for catching an exception in your case would be:
@try {
for (i=0; i <= stringLength; i++) {
unichar currentCharacter = [string characterAtIndex:i];
}
}
@catch (NSException *exception) {
NSLog(@"uh oh..");
// handle the exception here
}
That will catch any exception thrown, not just NSRangeException. In many languages you could do be more selective with syntax like @catch (NSRangeException *exception)
, but unfortunately not in Objective-C. This is because NSRangeException is not defined as a subclass of NSException, but it is instead an NSString constant which will appear in the -name value of an NSException. To be more selective in Objective-C you would need to do something like:
@catch (NSException *exception) {
if ([[exception name] isEqualToString:NSRangeException]) {
NSLog("got an NSRangeException");
// handle the exception here
} else {
NSLog("got an exception we can't handle so pass it down the chain");
@throw exception;
}
}
As you can see, it can get quite clumsy catching exceptions so it is always best to try avoiding them. If this code triggers an NSRangeException, something very exceptional (and probably beyond your control) must be happening:
for (i=0; i < [string length]; i++) {
unichar currentCharacter = [string characterAtIndex:i];
...}