0

I have a for loop.

for (i=0; i <= stringLength; i++) {

unichar currentCharacter = [string characterAtIndex:i];

...}

I understand from the documentation that characterAtIndex: will usually return a value of the type 'unichar' but if our index is out of bounds an NSRangeException is returned.

Being cautious, I'd like to check whether [string characterAtIndex:i] is returning an NSRangeException or not before assigning to return value to currentCharacter.

The first thing I tried was this:

if ([string characterAtIndex:i] != NSRangeException)

...but it doesn't work because, from my understanding, the method usually returns an int and I'm comparing it to NSRangeException, which is a string.

I thought about [string characterAtIndex:i] isKindOfClass:...] but that won't work because [string characterAtIndex:i] is not an NSObject. So, uh, how do I test for the exception?

Should I be testing for the exception? How do I test for the type of the returned value if it's sometimes a primitive and sometimes an NSObject?

4

2 回答 2

1

嗨奥利弗,我只是偶然发现了这个问题,并认为我会回答它,但我希望你从那以后已经解决了,并且没有被困在这个问题上 6 个月;)

首先,假设stringLength == [string length]您需要检查索引是否严格小于stringLength,而不是小于或等于,即:

for (i=0; i < stringLength; i++) {

  unichar currentCharacter = [string characterAtIndex:i];

...}

例如,一个 5 个字符的字符串有 5 个有效索引;0、1、2、3 和 4。

该修复程序应该可以阻止您获得异常,但这里有一些关于异常的更多解释(我在注意到您在索引中的非一错误之前写的):

异常不像正常的返回值,它们就像一个特殊的紧急通道,一个函数可以通过它通知它的调用者一个错误条件,而不必将一个错误条件塞进它的正常返回值中。

术语是异常不会“返回”,而是“引发”或“抛出”(取决于语言)。然后“捕获”或“拯救”异常(取决于语言)。

异常应该只在特殊情况下使用,如果有某种方法可以避免异常(通过清理输入),你应该首先这样做。尽可能避免异常的另一个原因是,在某些语言中,捕获异常的过程效率不高,并且还可能使内存分配有点悬而未决。

但在特殊情况下,它们是向调用函数发出错误信号的有用方法,而不必设法在返回值范围内表达错误条件。

所以,关于实用性。在您的情况下捕获异常的语法是:

@try {
  for (i=0; i <= stringLength; i++) {
    unichar currentCharacter = [string characterAtIndex:i];
  }
} 
@catch (NSException *exception) {
  NSLog(@"uh oh..");
  // handle the exception here
}

这将捕获任何抛出的异常,而不仅仅是 NSRangeException。在许多语言中,您可以对诸如@catch (NSRangeException *exception). 这是因为 NSRangeException 没有被定义为 NSException 的子类,而是一个 NSString 常量,它将出现在 NSException 的 -name 值中。要在 Objective-C 中更具选择性,您需要执行以下操作:

@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;
  }
}

如您所见,捕获异常可能会变得非常笨拙,因此最好尽量避免它们。如果这段代码触发了 NSRangeException,那么一定会发生一些非常异常(并且可能超出您的控制)的事情:

for (i=0; i < [string length]; i++) {

  unichar currentCharacter = [string characterAtIndex:i];

...}
于 2013-12-11T02:29:35.493 回答
0

还值得注意的是,您基本上不应该对可变字符串执行此操作。制作一个不可变的副本。如果您真的想尝试使用不可变字符串来执行此操作,则应从末尾向后迭代。在 for 循环迭代标准中断言长度没有改变也是合理的。

于 2013-12-11T05:24:48.153 回答