IOS4 note 11 (三)

IOS4 note 11 (3)

 

NSString and Friends

NSNotFound is a constant integer indicating that some requested element was not found. For example, if you ask for the index of a certain object in an NSArray and the object isn’t present in the array, the result is NSNotFound.

 

An NSString  can  be  searched  using  various  rangeOf... methods, which  return  an NSRange. In addition, NSScanner lets you walk through a string looking for pieces that fit certain criteria; for example, with NSScanner (and NSCharacterSet) you can skip past everything in a string that precedes a number and then extract the number. Starting with  iOS  3.2,  the  rangeOfString:  family  of  search methods  can  specify  an  option NSRegularExpressionSearch, which lets you search using a regular expression; in iOS 4, regular  expressions  are  fully  supported  as  a  separate  class,  NSRegularExpression (which uses NSTextCheckingResult to describe match results).

 

In this example from one of my apps, the user has tapped a button whose title is something like “5 by 4” or “4 by 3”. I want to know both numbers; one tells me how many rows the layout is to have, the other how many columns. I use an NSScanner to locate the two numbers:

NSString* s = [as buttonTitleAtIndex:ix];

NSScanner* sc = [NSScanner scannerWithString:s];

int rows, cols;

[sc scanInt:&rows];

[sc scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet]

                        intoString:nil];

[sc scanInt:&cols];

If I were writing this same code to run only on iOS 4, I might do the same thing using a regular expression:

 

NSString* s = [as buttonTitleAtIndex:ix];

int rowcol[2]; int* prowcol = rowcol;

NSError* err = nil;

NSRegularExpression* r = [NSRegularExpression regularExpressionWithPattern:@"\\d"

                                                                      options:0

                                                                            error:&err];

// error-checking omitted

for (NSTextCheckingResult* match in [r matchesInString:s

                                                     options:0

                                                          range:NSMakeRange(0, [s length])])

    *prowcol++ = [[s substringWithRange: [match range]] intValue];

 

The syntax seems oddly tortured, though, because we must convert each match from an NSTextCheckingResult to a range, then to a substring of our original string, and finally to an integer.

 

String drawing  in  a  graphical  context  can  be  performed  simply  with  methods provided through  the UIStringDrawing  category on NSString.

 

 

NSDate and Friends

 

An  NSDate  is  a  date  and  time,  represented  internally  as  a  number  of  seconds (NSTimeInterval) since some reference date. Calling [NSDate date] gives you a date object for the current date and time; other date operations may involve NSDateComponents and NSCalendar and can be a bit tricky because calendars are complicated (see the Date and Time Programming Guide).

You will also likely be concerned with dates represented as strings. Creation and parsing of  date  strings  involves  NSDateFormatter,  which  uses  a  format  string  similar  to NSString’s stringWithFormat. A complication is added by the fact that the exact string representation of a date component or format can depend upon the user’s locale, consisting of language, region format, and calendar settings. (Actually, locale considerations can also play a role in NSString format strings.)

 

In this example from one of my apps, I prepare the content of a UILabel reporting the date and time when our data was last updated. The app is not localized — the word “at” appearing  in  the string  is always going  to be  in English — so  I want complete control of the presentation of the date and time components as well. To get it, I have to insist upon a particular locale:

NSDateFormatter *df = [[NSDateFormatter alloc] init];

if ([[NSLocale availableLocaleIdentifiers] indexOfObject:@"en_US"] != NSNotFound) {

    NSLocale* loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

 

    [df setLocale:loc]; // force English month name and time zone name if possible

}

[df setDateFormat:@"d MMMM yyyy 'at' h:mm a z"];

NSString* lastUpdated = [df stringFromDate: [NSDate date]];

 

NSNumber

An NSNumber is an object that wraps a numeric value (including BOOL). 

 

 

NSValue

NSValue is NSNumber’s superclass. Use it for wrapping nonnumeric C values such as structs. Convenience methods provided by  through  the NSValueUIGeometryExtensions  category on NSValue  (see  the NSValue UIKit Additions Reference)  allow  easy wrapping  and unwrapping of CGPoint, CGSize, CGRect, CGAffineTransform,  and UIEdgeInsets; additional categories allow easy wrapping and unwrapping of CATransform3D, CMTime, CMTimeMapping, and CMTimeRange.You are unlikely to need to store any other kind of C value in an NSValue, but you can if you need to.

 

 

NSData

NSData is a general sequence of bytes. It is immutable; the mutable version is its subclass NSMutableData.

In practice, NSData tends to arise in two main ways:

1)When downloading data from the Internet. For example, the NSURLConnection class supplies whatever it retrieves from the Internet as NSData. Transforming it from there into (let’s say) a string, specifying the correct encoding, would then be up to you.

2)When storing an object as a file or in user preferences. For example, you can’t store a UIColor value directly into user preferences. So if the user has made a color choice and  you  need  to  save  it,  you  transform  the  UIColor  into  an  NSData  (using NSKeyedArchiver) and save that:

[[NSUserDefaults standardUserDefaults] registerDefaults:

    [NSDictionary dictionaryWithObjectsAndKeys:

        [NSKeyedArchiver archivedDataWithRootObject:[UIColor blueColor]],

        @"myColor",

        nil]];