The fastest reliable way to enumerate characters in an NSString
I know of is to use this relatively little-known Core Foundation gem hidden in plain sight (CFString.h).
NSString *string = <#initialize your string#>
NSUInteger stringLength = string.length;
CFStringInlineBuffer buf;
CFStringInitInlineBuffer((__bridge CFStringRef) string, &buf, (CFRange) { 0, stringLength });
for (NSUInteger charIndex = 0; charIndex < stringLength; charIndex++) {
unichar c = CFStringGetCharacterFromInlineBuffer(&buf, charIndex);
}
If you look at the source code of these inline functions, CFStringInitInlineBuffer()
and CFStringGetCharacterFromInlineBuffer()
, you'll see that they handle all the nasty details like CFStringGetCharactersPtr()
returning NULL
, CFStringGetCStringPtr()
returning NULL
, defaulting to slower CFStringGetCharacters()
and caching the characters in a C array for fastest access possible. This API really deserves more publicity.
The caveat is that if you initialize the CFStringInlineBuffer
at a non-zero offset, you should pass a relative character index to CFStringInlineBuffer()
, as stated in the header comments:
The next two functions allow fast access to the contents of a string, assuming you are doing sequential or localized accesses. To use, call CFStringInitInlineBuffer()
with a CFStringInlineBuffer
(on the stack, say), and a range in the string to look at. Then call CFStringGetCharacterFromInlineBuffer()
as many times as you want, with a index into that range (relative to the start of that range). These are INLINE functions and will end up calling CFString
only once in a while, to fill a buffer. CFStringGetCharacterFromInlineBuffer()
returns 0 if a location outside the original range is specified.