Thursday, September 30, 2010

Creating a GUID or UUID in Objective-C

I recently needed to generate unique IDs to be sent from an iPhone app to a web service. Rather than come up with my own scheme, I looked around for a way to generate a UUID (or GUID if you're from the Windows world) on iOS.

Turns out that Core Foundation includes a set of functions for working with UUIDs naturally called CFUUID. I needed a string representation of the UUID so I quickly rolled this method to generate it:
// return a new autoreleased UUID string
- (NSString *)generateUuidString
{
  // create a new UUID which you own
  CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);

  // create a new CFStringRef (toll-free bridged to NSString)
  // that you own
  NSString *uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuid);
  
  // transfer ownership of the string
  // to the autorelease pool
  [uuidString autorelease];

  // release the UUID
  CFRelease(uuid);

  return uuidString;
}
Not too hard to do if you're familiar with Core Foundation conventions.

Tuesday, September 28, 2010

Objective-C Tuesdays: searching in strings

Last week we looked at creating substrings of C strings and NSStrings. Today we look at another common string operation: searching within a string.

Find a character in a C string
As with all operations on C strings, searching requires you to deal with pointers. To find the first occurrence of a character in a C string, use the strchr() function. If the character is found, a pointer to that character is returned. If the character isn't present in the string, NULL is returned.
// find a character in a C string
char const *s = "foobar";

char const *character = strchr(s, 'b');
if (character) {
  NSLog(@"Found b");
} else {
  NSLog(@"Didn't find b");
}
// prints "Found b"
As we saw last week when we looked at substrings, the pointer returned by strchr() is effectively a substring of the source string starting at the first occurrence of the character you were searching for:
char const *s = "foobar";

char const *substring = strchr(s, 'b');
if (substring) {
  NSLog(@"The substring is %s", substring);
}
// prints "The substring is bar"
Once you find the character you're looking for, it's common to want to create a substring containing everything up to that position in the string:
char const *filename = "myfile.txt";

char const *dot = strchr(filename, '.');
if (dot) {
  size_t length = dot - filename;
  char *baseFilename = calloc(length + 1, sizeof(char));
  if (baseFilename) {
    strncpy(baseFilename, filename, length);
    NSLog(@"The base filename is %s");
  }
}
// prints "The base filename is myfile"
You use the difference between the two string pointers to calculate the number of chars up to (but not including) the character you searched for. After allocating a buffer to hold the new substring (and the null terminator), you use the strncpy() function to copy the first part of the source string. Because we called calloc(), the last char in our buffer is already set to zero; if you use malloc() or a fixed buffer instead, you need to remember to set the null terminator since strncpy() isn't guaranteed to do it for you.

Very often, you want to find the last occurrence of a character; you can use the strrchr() function to search in reverse:
// find a character in reverse
char const *filename = "myfile.txt";

char const *extension = strrchr(filename, '.');
if (extension) {
  NSLog(@"The extension is %s", extension);
}
// prints "The extension is .txt"

Find one C string in another
To find the first occurrence of one C string in another, use the strstr() function. Like strchr(), it returns a pointer to the first occurrence of the string, or NULL if it wasn't found.
// find one C string in another
char const *s1 = "The quick brown fox";

char const *s2 = strchr(s1, "ick");
if (s2) {
  NSLog(@"Found ick");
} else {
  NSLog(@"Didn't find ick");
}
// prints "Found ick"
Unfortunately the C standard library doesn't have a strrstr() function to search for the last occurrence of one string in another. You'll need to roll your own by calling strstr() in a loop until you reach the end of the string. (The implementation of this is left as an exercise for the reader, or better yet convert your C string to an NSString and keep reading :-)

C string encoding issues
The standard library functions for searching C strings work great with ASCII and similar single byte encodings. If you need to search inside UTF-8 encoded C strings, you'll quickly realize that strchr() and strrchr() are only useful for finding the basic ASCII characters (which are also valid UTF-8 characters). If you need to find non-ASCII characters like 'é', you'll need to use strstr() to search for the byte sequence that UTF-8 uses to represent it ("\xc3\xa9" for 'é'). Even then, Unicode characters like 'é' can be represented two ways: as the single Unicode character 'é' or as the base character 'e' followed by the combining character '´'. In general, it's better to use a C library designed to deal with the encoding such as the International Components for Unicode for handling UTF-8 encoded strings. Or if you're developing for iOS or Mac OS X, use NSString instead.

Find one NSString in another
The NSString class doesn't have separate methods to search for a single character or a string; you use -rangeOfString: to do either:
// find a character in an NSString
NSString *s = @"foobar";

NSRange range = [s rangeOfString:@"b"];
if (range.location != NSNotFound) {
  NSLog(@"Found b at %u", range.location);
}
// prints "Found b at 3"
Searching for the last occurrence of a string is done using the related method -rangeOfString:options: with the NSBackwardsSearch option.
// find last occurrence in an NSString
NSString *s = @"The rain in Spain falls mainly on the plain";

NSRange range = [s rangeOfString:@"ain" options:NSBackwardsSearch];
if (range.location != NSNotFound) {
  NSLog(@"Found ain at %u", range.location);
}
// prints "Found ain at 40"
The options are a combination of the following bit flags: NSCaseInsensitiveSearch, NSLiteralSearch, NSBackwardsSearch and NSAnchoredSearch. You use the bitwise or (|) operator to combine them together, or pass in zero for no options.

Use the NSCaseInsensitiveSearch option to find the first match, ignoring the case of both strings. The NSLiteralSearch option is used when you want to match a specific Unicode string form, such as the single character 'é' (Unicode character U+00E9) and not match equivalent character sequences like 'e' + '´' (Unicode characters U+0065 and U+0301). Most applications won't care about this option, but it's really handy when you need it.

NSAnchoredSearch checks for a match only at the start of the string (or the end if combined with NSBackwardsSearch). This option is occasionally handy, but the methods -hasPrefix: and -hasSuffix: are easier to read equivalents.
// anchored search
NSString *s = @"The rain in Spain falls mainly on the plain";

NSRange range = [s rangeOfString:@"ain" 
                         options:NSAnchoredSearch];
if (range.location == NSNotFound) {
  NSLog(@"Doesn't start with ain");
}
// prints "Doesn't start with ain"

// same thing using -hasPrefix:
if ( ! [s hasPrefix:@"ain"]) {
  NSLog(@"Doesn't have prefix ain");
}
// prints "Doesn't have prefix ain"


// now from the end
range = [s rangeOfString:@"ain"
                 options:NSAnchoredSearch | NSBackwardsSearch];
if (range.location != NSNotFound) {
  NSLog(@"Ends with ain");
}
// prints "Ends with ain"

// same thing using -hasSuffix:
if ([s hasSuffix:@"ain"]) {
  NSLog(@"Has suffix ain");
}
// prints "Has suffix ain"
There are two other variations of -rangeOfString:. The first, -rangeOfString:options:range:, allows you to search within a section of a larger string without having to create a substring.

The second, -rangeOfString:options:range:locale:, allows you to specify a locale as well as a range. In most cases you want to use the current locale, which is taken from the language setting on the user's device. The other variations of -rangeOfString: use the current locale, and you can pass nil for the locale to use the current one. Sometimes you know that the string contains text in a particular language, in an app that teaches German for instance. In this case you should specify a locale when searching the string; the locale can affect how text is matched, especially when using the NSCaseInsensitiveSearch option.

Next week, we'll look at replacing characters in C strings and NSStrings.

Friday, September 24, 2010

iPad Friday: September 24, 2010

Hello and happy Friday.  Today's collection of iPad wallpapers continue our look at photos from around the neighborhood.  Cheers!

(click an image for the full-size wallpaper)






iPhone Friday: September 24, 2010

Hello and happy Friday.  Today's collection of iPhone wallpapers continue our look at photos from around the neighborhood.  Cheers!

(click an image for the full-size wallpaper)






Tuesday, September 21, 2010

Objective-C Tuesdays: slicing and dicing strings

Last time, we looked at C string and NSString comparison and equality. Today we'll examine functions and methods for creating substrings of C strings and NSStrings.

Substrings of C strings
Creating a C string requires you to explicitly manage the memory the string lives in. Depending on how long you need to keep the C string around, you can use either a fixed buffer or a dynamically allocated one. As always with C strings, you need to be careful not to write past the end of the buffer.

Creating a substring that starts at the beginning of the source string is straight forward: use the strncpy() function. There's a big gotcha when using strncpy() to copy a substring: it doesn't automatically add a null terminator to the destination. Here's an example of copying the first three characters of a C string into a fixed buffer:
// copy substring from start of source
// using a fixed buffer
char const *source = "foobar";
char buffer[4];                // make sure buffer includes
                               // space for null terminator

strncpy(buffer, source, 3);    // copy first 3 chars from source
buffer[3] = '\0';              // remember to add null terminator
Using a dynamic buffer is similar, but requires explicit memory management.
// copy substring from start of source
// using a dynamic buffer
char const *source = "foobar";
char *buffer = malloc(4 * sizeof(char)); // make sure buffer includes
                                         // space for null terminator

if ( ! buffer) {
  // must handle allocation failure
}

strncpy(buffer, source, 3); // copy first 3 chars from source
buffer[3] = '\0';           // remember to add null terminator

// use buffer ...

// don't forget to free() buffer when done
free(buffer);
You can make this a little more compact by using calloc() instead of malloc(). The calloc() function allocates memory using malloc(), then clears all the bytes to zero. As long as you make sure to include an extra byte at the end, your new substring will be null terminated:
// copy substring from start of source
// using a dynamic buffer 
// allocated with calloc()
char const *source = "foobar";
char *buffer = calloc(4, sizeof(char)); // make sure buffer includes
                                        // space for null terminator

if ( ! buffer) {
  // handle allocation failure
}

strncpy(buffer, source, 3); // copy first 3 chars from source
                            // last char in buffer is already '/0'

// use buffer ...

// don't forget to free() buffer when done
free(buffer);
There's not a huge difference between malloc() and calloc(), so choose whichever one you're more used to using, or use calloc() if you don't have a strong preference. The cost of clearing a range of memory to zeros is so tiny as to not be worth considering in most circumstances, and knowing that your buffer is initialized to zeros can be handy.

There's no standard C function for getting a substring that starts somewhere in the middle of the source string, because one isn't needed -- you simply move the pointer from the start of the string. Here's an illustration:
// C strings are pointers
char const *string = "foobar";

NSLog(@"'%s'", string);
// prints out 'foobar'

char const *substring = string + 3;
NSLog(@"'%s'", substring);
// prints out 'bar'
You can add an integer value to the C string pointer to get a pointer to the middle of the source string -- just be careful not to go off the end of the string! If you only need the substring for a short period of time, or if you know that the source string will live longer than the substring and never change, it's safe to simply create a substring this way. However, you can introduce weird bugs if you get this wrong. When in doubt, copy the substring to a new buffer:
// create a substring from the middle of a string
char const *source = "foobar";
char const *substringSource = source + 3;
size_t charCount = strlen(substringSource) + 1;
char *buffer = calloc(charCount, sizeof(char));

if ( ! buffer) {
  // handle allocation failure
}

strcpy(buffer, substringSource);

// use buffer ...

free(buffer);
Here we calculate the starting point by simply adding 3 to the string pointer source. Then we figure out the number of chars we need to allocate using the strlen() function, remembering to add 1 for the null terminator character. After allocating memory, the strcpy() function copies all the characters from substringSource into buffer. Unlike strncpy(), strcpy() will copy the null terminator, so this code will be the same whether we use calloc() or malloc() to allocate the buffer.

If you need to grab a substring that falls between the beginning and end of a longer string, you combine these two techniques: use pointer arithmetic to get a pointer to the start of the substring, then use strncpy() to copy just the characters you need.

Warning: beware encoding issues!
Slicing and dicing C strings is easy when you're using a single byte encoding like ASCII. If you're using a multibyte encoding like UTF-8, you need to be aware that one logical character may require two or more bytes. If you want to omit the first three logical characters in a string, you need to examine each byte from the start of a string to determine if it's part of a multibyte sequence, and adjust your string pointer accordingly. If you need to work with multibyte encodings, I recommend finding an appropriate library for the encoding, such as the International Components for Unicode for working with Unicode encodings. Or better yet, transform your C strings into NSStrings.

Substrings of NSStrings
There are three ways to get a substring of an NSString. First we'll look at taking a substring from the start of an NSString:
// create a substring from the start of source
NSString *source = @"foobar";

NSString *substring = [source substringToIndex:3];
// substring is "foo"
The substring returned by -substringToIndex: is autoreleased. You should -retain or -copy it if you need to hold on to it.

Similarly, to get a substring that starts in the middle of an NSString and goes to the end:
// create a substring to the end of source
NSString *source = @"foobar";

NSString *substring = [source substringFromIndex:3];
// substring is "bar"
Finally, the general purpose way to create a substring of an NSString is the -substringWithRange: method, which uses an NSRange structure, which is defined something like this:
// NSRange structure
struct NSRange {
  NSUInteger location;
  NSUInteger length;
}
When used with -substringWithRange: method, the NSRange's location field is the zero-based index of the first character to be included in the substring, and the length field is the number of characters to include in the substring. Here are some examples:
// -substringWithRange: examples
NSString *source = @"foobar";
NSRange range;

range.location = 0;
range.length = 3;
NSString *frontHalf = [source substringWithRange:range];
// frontHalf is "foo"

range.location = 3;
range.length = 3;
NSString *backHalf = [source substringWithRange:range];
// backHalf is "bar"

range.location = 2;
range.length = 2;
NSString *middle = [source substringWithRange:range];
// middle = "ob"
One word of caution: if the range you give falls outside the receiver (the source string), this method will raise an NSRangeException.

Setting the fields of NSRange is fairly verbose; it's generally more convenient to use the NSMakeRange() function to create the NSRange structure instead.
// NSMakeRange() example
NSString *source = @"foobar";

NSString *frontHalf = [source substringWithRange:NSMakeRange(0, 3)];
// frontHalf is "foo"

NSString encoding mostly not a worry
Internally, NSString uses UTF-16 encoding. Although UTF-16 is a variable length encoding like UTF-8, characters from the basic multilingual plane are all two bytes (one word) in length. If you're certain that your NSString contains only basic multilingual plane characters, then methods like -length and -substringWithRange: will work exactly as you expect them. However, if your NSString includes characters outside the basic multilingual plane, it will contain surrogate pairs, which are multi-word sequences that represent a single character. You'll find that -length tells you the number of words rather than logical characters, and if you're not careful, methods like -substringWithRange: can split a surrogate pair in half, leaving you with an invalidly encoded string.

Unless your application needs to work with characters outside the basic multilingual plane, the easiest solution is to filter out such characters when you accept data from a source outside your app. Since the basic multilingual plane contains all the characters in common use in most modern languages, this is sufficient for many applications. The standard iOS input keyboards limit the user to characters in the basic multilingual plane, but if your app reads data from the network, such as an RSS feed you don't control, you need to watch out for this.

Next time, we'll look at searching in C strings and NSStrings.

Tuesday, September 14, 2010

Objective-C Tuesdays: string comparison and equality

Welcome back after an end-of-Summer hiatus. Last time we looked at concatenating strings in Objective-C. Today we look at another common string operation: comparison.

Identity
Comparing two variables or objects can sometimes be a tricky proposition. There are several different senses of equality. The most fundamental type of equality is identity: do two variables represent the same thing in memory. Identity only makes sense for reference types, like C strings, NSStrings and other pointer types. Value types like ints always designate separate things in memory. In C and Objective-C, identity equality is determined by comparing pointer values using the == operator.
// comparing two strings for identity
char const s1 = "foo";
char const s2 = s1;
if (s1 == s2) {
  NSLog(@"s1 is identical to s2");
}

NSString *s3 = @"foo";
NSString *s4 = @"bar";
if (s3 != s4) {
  NSLog(@"s3 is not identical to s4");
}

Equivalence
A more useful type of equality is equivalence of value: do two variables represent equivalent data. Equivalence is useful when comparing value types as well as reference types, and is usually what programmers think of when comparing two strings.

For C strings, the primary equivalence test is done with the strcmp() function. The strcmp() function compares the data of two C strings char by char; if two C strings represent the same sequence of char values in memory, they are equivalent and strcmp() returns zero.
// checking two C strings for equal value
char const *s1 = "foo";
char const *s2 = "bar";

if (strcmp(s1, s2) == 0) {
  NSLog(@"s1 is equivalent to s2");
} else {
  NSLog(@"s1 is not equivalent to s2");
}
In addition to checking for equivalence, strcmp() also categorizes the sort order of the two C strings. If the first argument comes before the second, a negative value is returned; if the first argument comes after the second, a positive value is returned. The strcmp() function uses a lexicographic comparison, which means that the comparison is strictly on the basis of the integer values of the chars in the C strings. For ASCII strings, the string "2" (ASCII code 50) comes before "A" (ASCII code 64), which precedes "a" (ASCII code 97). Many sorting algorithms, including the qsort() function in the C standard library, require a function like strcmp().
// using strcmp() result

int compareResult = strcmp(s1, s2);
if (compareResult < 0) {
  NSLog(@"s1 comes before s2");
} else if (compareResult > 0) {
  NSLog(@"s1 comes after s2");
}

Sometimes you only want to see if two strings have a common prefix, or you're working with character buffers that aren't null terminated. The strncmp() function will compare a limited number of characters, stopping early if it encounters a null terminator in either string. Thus these two strings are equivalent when the first three characters are compared:
if (strncmp("foo", "fooey", 3) == 0) {
  NSLog(@"both start with foo");
}
// prints "both start with foo"

When sorting with strncmp(), short strings come first:
if (strncmp("foo", "fooey", 5) < 0) {
  NSLog(@"foo comes before fooey");
}
// prints "foo comes before fooey"

Case Insensitive
In languages that have upper and lower case letters, you often need to do a case insensitive comparisons. The C standard library doesn't define a case insensitive string comparison function, but one is part of the POSIX standard, and most compiler vendors and operating systems include one. The POSIX version is called strcasecmp(). Most modern Unix and Linux systems (including iOS and Mac OS X) have strcasecmp() available in the standard library. Older Unix systems and other operating systems may call this function stricmp() or strcmpi(). There is usually also a length limited version called strncasecmp() or strnicmp().

The case insensitive comparison functions usually compare only ASCII characters, which limits their usefulness.
// case insensitive comparison
char const *s = "<HTML><HEAD>...";

if (strncasecmp(s, "<html>", 6) == 0) {
  NSLog(@"looks like HTML");
}

Encoding Issues
The strcmp() function was created in the era when most computers used ASCII or other simple single byte encodings. In ASCII, there is only one byte sequence that represents any particular character sequence. This isn't true of many modern encodings, including Unicode. The Unicode character set contains both accented characters such as "é" as well as a combining accent character "´", so there are two ways to represent "é" in UTF-8 encoding:

Address646566
Character'é'
Value195169
Character'e''´'
Value101204129
Obviously a lexicographic comparison function like strcmp() will not see these two strings as equivalent. Accounting for this requires performing normalization on the Unicode characters in the string before doing the comparison. Unicode has several different types of normalization, which we won't dive into here. If you need to do a lot of low level processing of UTF-8 or other Unicode encoded text, you should look at the International Components for Unicode, a library of C functions for Unicode processing that is included as part of iOS. Better yet, in most cases you should use NSStrings when working with text.

NSString equality
The NSString class defines the -isEqualToString: instance method for testing if an NSString is equivalent to another NSString:
// compare two NSStrings
NSString *s1 = @"foo";
NSString *s2 = @"bar";

if ( [s1 isEqualToString:s2] ) {
  NSLog(@"The strings are equivalent.");
}
You can also use the -isEqual: instance method defined by NSObject to compare two NSStrings, or to compare an NSString with any other object:
// compare two NSStrings using -isEqual:
NSString *s1 = @"foo";
NSString *s2 = @"bar";

if ( [s1 isEqual:s2] ) {
  NSLog(@"The strings are equivalent.");
}
The difference between the two methods is in their declarations. The -isEqualToString: method is only for comparing one NSString to another; it's declaration looks like:
// declaration of -isEqualToString:
- (BOOL)isEqualToString:(NSString *)aString
The -isEqual: method is for comparing any kind of NSObject to another object; it's declaration looks like:
// declaration of -isEqual:
- (BOOL)isEqual:(id)anObject
It's possible to use -isEqual: to compare an NSString with an object of a different type, such as an NSNumber:
NSString *fiveString = @"5";
NSNumber *fiveNumber = [NSNumber numberWithInt:5];

if ( [fiveString isEqual:fiveNumber] ) {
  NSLog(@"fiveString equals fiveNumber");
} else {
  NSLog(@"Strings aren't equivalent to numbers, silly!");
}
You might hope that the NSString "5" is equivalent to the NSNumber "5" but unfortunately they are not; the code above will print out "Strings aren't equivalent to numbers, silly!". In general, objects of different classes aren't considered to be equivalent with one common exception: immutable classes like NSString can be equivalent to their mutable subclasses (NSMutableString in this case) and vice versa.
NSString *fiveString = @"5";
NSMutableString *fiveMutableString = [NSMutableString stringWithString:@"5"];

if ( [fiveString isEqual:fiveMutableString] ) {
  NSLog(@"immutable and mutable strings can be equivalent");
}
And since NSMutableString is a subclass of NSString, you can also use -isEqualToString: to compare them:
if ( [fiveString isEqualToString:fiveMutableString] ) {
  NSLog(@"immutable and mutable strings can be equivalent");
}

-compare:
In addition to testing for equivalence using -isEqual: or -isEqualToString:, you can also discover the relative order of two NSString objects using the -compare: family of methods. The -compare: method is very similar to the strcmp() method in C. The -compare: method returns a NSComparisonResult value, which is simply an integer value. Similar to strcmp(), -compare: will return zero if the two NSStrings are equivalent, though you can also use the constant NSOrderedSame instead of zero:
// compare two NSStrings
NSString *s1 = @"foo";
NSString *s2 = @"bar";

if ( [s1 compare:s2] == NSOrderedSame] ) {
  NSLog(@"s1 is equivalent to s2");
} else {
  NSLog(@"s1 is not equivalent to s2");
}
Like strcmp(), if the receiver of the -compare: message (the first NSString) comes before the first argument (the second NSString), negative one is returned; if the receiver comes after the first argument, positive one is returned. The constants NSOrderedAscending and NSOrderedDescending can be used instead of -1 and 1 respectively.
// using NSComparisonResult

NSComparisonResult comparisonResult = [s1 compare:s2];
if (comparisonResult == NSOrderedAscending) {
  NSLog(@"s1 comes before s2");
} else if (comparisonResult == NSOrderedAscending) {
  NSLog(@"s1 comes after s2");
}

Case Insensitive -compare:
To test the equivalence of two NSString objects in a case insensitive manner, use -compare:options: with the NSCaseInsensitiveSearch flag.
// case insensitive compare
NSString *s1 = @"foo";
NSString *s2 = @"FOO";

if ( [s1 compare:s2 options:NSCaseInsensitiveSearch] == NSOrderedSame) {
  NSLog(@"s1 is equivalent to s2");
}
Since case insensitive comparison is a common operation, NSString has a convenience method, -caseInsensitiveCompare: which does the same thing.
// case insensitive compare
NSString *s1 = @"foo";
NSString *s2 = @"FOO";

if ( [s1 caseInsensitiveCompare:s2] == NSOrderedSame) {
  NSLog(@"s1 is equivalent to s2");
}

Unicode and -compare:
By default, NSString is pretty smart about Unicode and automatically understands things like Unicode combining characters. For instance, you can represent é two ways, but NSString knows that they represent equivalent strings:
// comparing equivalent Unicode strings
NSString *eAcute = @"\u00e9";      // single character 'é'
NSString *ePlusAcute = @"e\u0301"; // 'e' + combining '´'

if ( [eAcute isEqualToString:ePlusAcute] ) {
  NSLog(@"'é' is equivalent to 'e' + '´'");
}
This can be surprising if you've only worked with ASCII or other single byte encodings. With NSString, you can't assume that equivalent strings have the same length and character sequence. Usually you don't care about the Unicode representation, but occasionally it's important. You can use the NSLiteralSearch flag along with -compare:options: to do a lexicographic comparison that compares strings character value by character value.

// lexicographic comparison of Unicode strings

if ( [eAcute compare:ePlusAcute options:NSLiteralSearch] != NSOrderedSame) {
  NSLog(@"'é' is not lexicographically equivalent to 'e' + '´'");
}

combining options
The options constants used in the -compare:options: method are bit flags. You combine them using the bitwise or operator (|).
// using multiple options
NSString *eAcute = @"\u00e9";        // 'é'
NSString *capitalEAcute = @"\u00c9"; // 'É'

if ( [eAcute compare:capitalEAcute 
             options:NSCaseInsensitiveSearch | NSLiteralSearch] 
         != NSOrderedSame) 
{
  NSLog(@"'é' is equivalent to 'É'");
}

comparing substrings
If you only want to compare parts of two NSString objects, you can use -compare:options:range: method and specify an NSRange structure. The NSRange structure is composed of two parts: a starting location field named loc and a length field named len. Usually it's convenient to use the NSMakeRange() function to generate the NSRange.
// compare substrings
NSString *s1 = @"foo";
NSString *s2 = @"fooey";

if ( [s1 compare:s2 
         options:0 
           range:MakeRange(0, 3)] == NSOrderedSame)
{
  NSLog(@"both strings start with 'foo'");
}
You pass in zero for the options to use the default comparison. -compare:options:range: is similar to strncmp() with one important difference: the NSRange you give must fall completely inside the receiver (the first string) or an NSRangeException will be thrown.

comparing using a specific locale
By default, the -compare: methods use the current locale to determine the ordering of two strings. The current locale is controlled by the user when they set their language and region for their iOS device. Most of the time you should respect the user's settings, but sometimes it's appropriate to compare strings using a fixed locale. Perhaps your app teaches French vocabulary and you want your French word list to sort in standard French order whether the user's phone is set to English, German or Japanese. In French, accented letters at the end of a word sort before accented letters earlier in a word, thus "coté" should come before "côte". If you use the default locale, the result of comparing "coté" and "côte" varies but will probably not give you the correct ordering.
// compare using default locale
NSString *coteAcute = @"cot\u00e9";      // "coté"
NSString *coteCircumflex = @"c\u00f4te"; // "côte"

if ( [coteAcute compare:coteCircumflex] == NSOrderedAscending) {
  NSLog(@"Not using a French locale");
}
To remedy this, you can set the locale explicitly when you do your comparison:
// compare using specific locale
NSLocale *frenchLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"] autorelease];
NSComparisonResult comparisonResult = [coteAcute compare:coteCircumflex 
                                                 options:0 
                                                   range:NSMakeRange(0, 4)
                                                  locale:frenchLocale];
if (comparisonResult == NSOrderedDescending) {
  NSLog(@"Using a French locale");
}

That sums up the options for comparing C strings and NSStrings. Next time, we'll look at slicing and dicing strings by creating substrings.

Friday, September 10, 2010

iPad Friday: September 10, 2010

Hello and happy Friday.  Today's collection of iPad wallpapers continue our look at photos from around the neighborhood.  Cheers!

(click an image for the full-size wallpaper)






iPhone Friday: September 10, 2010

Hello and happy Friday.  Today's collection of iPhone wallpapers continue our look at photos from around the neighborhood.  Cheers!

(click an image for the full-size wallpaper)






Friday, September 3, 2010

iPad Friday: September 3, 2010

Hello and happy Friday.  The past few weeks we've been looking at series of studies in 3D; light, shadows, geometric patterns and reflections.  As a departure from the rendered we are returning to our roots in the real—photography.  Please enjoy the following iPad wallpapers and we'll see you next week for more.

(click an image for the full-size wallpaper)






iPhone Friday: September 3, 2010

Hello and happy Friday.  The past few weeks we've been looking at series of studies in 3D; light, shadows, geometric patterns and reflections.  As a departure from the rendered we are returning to our roots in the real—photography.  Please enjoy the following iPhone wallpapers and we'll see you next week for more.

(click an image for the full-size wallpaper)