Chapter     10

Foundation Framework General Purpose Classes

The Foundation Framework defines a base layer of APIs that can be used for any type of Objective-C program. It includes root object classes, classes for basic data types such as strings, wrapper classes for primitive data types, and collection classes for storing and manipulating other objects, as well as classes for system information, networking, and other functionality. Mastering the Foundation Framework APIs is one of the keys to becoming a proficient Objective-C programmer. Part 3 will help you get there as you examine these APIs in depth.

The Foundation Framework evolved from the NeXTSTEP OpenStep APIs, created in 1993. These APIs included application layer Objective-C libraries, divided into the Foundation Kit and the Application Kit. They also established the “NS” prefix-naming convention used for these APIs. When Apple acquired NeXT Software in 1996, the Foundation Kit served as the basis for the existing Foundation Framework.

In this chapter, you will explore Foundation Framework classes that provide common, general-purpose functionality required by most Objective-C programs. OK, let’s get started!

Root Classes

A root, or base, class defines an interface and behaviors common to all classes below it in a class hierarchy. The Foundation Framework provides two root classes: NSObject and NSProxy. NSObject is the root class of most Objective-C class hierarchies, while NSProxy is a specialized class used to implement proxy objects. Both root classes adopt the NSObject protocol, which declares methods common to all Objective-C objects.

NSObject Protocol

The NSObject protocol specifies the basic API required for any Objective-C root class. As a protocol declares methods and properties that are not specific to any particular class, this design facilitates the definition of multiple root classes (even user-defined root classes). The methods declared by the NSObject protocol can be grouped into the following categories:

  • Identifying classes and proxies
  • Identifying and comparing objects
  • Describing objects
  • Object introspection
  • Sending messages

The protocol also declares a set of obsolete methods used for manual memory management. Because ARC is the preferred memory management mechanism, these methods should no longer be used.

NSObject

The NSObject class is the root class of most Objective-C hierarchies; in fact, almost all of the Foundation Framework classes are subclasses of NSObject. It defines a set of class and instance methods that provide the following functionality:

  • Basic object behaviors
  • (Object, class) creation and initialization
  • Dynamic (runtime system) features

You have used many of the NSObject methods in the preceding chapters, so by now you’re probably pretty familiar with some of the functionality this class provides. What you’ll do in the following paragraphs is examine some of the NSObject methods that I have yet to discuss in this book.

Basic Behaviors

The NSObject description class method returns a string that represents the contents of the class. The default implementation simply prints the name of the class. As an example, the following statement will display the string NSArray in the Xcode output pane.

NSLog(@"%@", [NSArray description]);

The NSObject protocol declares a description instance method; the default implementation (provided by the NSObject class) prints the object name and its address in memory. The debugDescription instance method returns a string that represents the contents of the object for presentation to the debugger; its default implementation is the same as that for the description instance method.

The isEqual: method returns a Boolean YES if the receiver and the input parameter (object) are equal. Two objects that are equal must have the same hash value. The default (NSObject) implementation returns YES if the receiver and the input parameter have the same memory address.

The hash method returns a value of type NSUInteger that can be used in a hash table structure. As noted earlier, two objects that are equal must have the same hash value. If hash values are used to determine the positions of objects in a collection, the value returned by the hash method of an object in a collection must not change while it is in the collection.

Sending Messages

NSObject defines a family of performSelector: instance methods used to send a message to an object. Each specifies a selector parameter identifying the message to send. The performSelector: method is equivalent to a standard Objective-C object message; for example, the following statements are equivalent:

[atom logInfo];
[atom performSelector:@selector(logInfo)];

The performSelector: method differs from a standard object message in that it enables you to send messages that are determined at runtime, as a variable selector value can be passed as the argument.

Several variations of the performSelector: method are declared in the NSObject protocol. These differ in the number of arguments (0–2) specified for the message (performSelector:, performSelector:withObject:, performSelector:withObject:withObject:). The NSObject class also defines multiple performSelector: methods. These provide additional functionality when sending a message to an object, specifically:

  • Thread selection (current, background, user-specified)
  • Method invocation semantics (synchronous, blocking)
  • Event processing mode
  • Method invocation delay

For example, the performSelector:withObject:afterDelay: method sends a message to an object after a specified delay. The following statement demonstrates use of this method to send a message to an object after a delay of 5 seconds.

[atom performSelector:@selector(logInfo) withObject:nil afterDelay:5.0];

Creation and Initialization

Now you’re going to examine a few NSObject methods used for class loading and initialization. The initialize class method is used to initialize a class after it is loaded but before it is first used—that is, before it or any class that inherits from it is sent its first message. This method is called on a class at most once during program execution; in fact, if the class is not used, the method is not invoked. The initialize method is thread-safe and always sent to all of a class’s superclasses before it is sent to the class itself. To prevent the possibility of the method being called twice (by a superclass in addition to the target class) the initialize method should be implemented using logic that verifies the caller is the target class, and not a superclass (as shown in Listing 10-1).

Listing 10-1.  NSObject initialize Method Design

+ (void)initialize
{
  if (self == [MyClass class])
  {
    // Initilization logic
  }
}

Listing 10-1 shows that the conditional test verifies that the initialization logic is performed only on a receiver whose class is that for which the initialize method is implemented.

The NSObject load class method, if implemented, is also invoked one time, after a class is loaded. It differs from the initialize method in several ways:

  • The load method is invoked very shortly after a class is loaded, prior to the initialize method. In fact, for classes that are statically linked (i.e., part of the program executable) the load method is called prior to the main() function. If the load method is implemented in a class packaged in a loadable bundle, it will be run when the bundle is dynamically loaded. Using the load method requires great care because it is called so early during application startup. Specifically, when this method is called, the program’s autorelease pool is (usually) not present, other classes may not have been loaded, and so forth.
  • The load method can be implemented for both classes and categories; in fact, every category of a class can implement its own load method. The initialize method should never be overriden in a category.
  • The load method is invoked one time, if implemented, after a class is loaded. The initialize method is invoked one time, if implemented, when a class receives its first message; if the class is not used, the method is not invoked.

The NSObject new class method allocates a new instance of an object and then initializes it. It combines the alloc and init methods in a single method. The following two object creation and initialization statements are equivalent.

Atom *atom = [[Atom alloc] init];
Atom *atom = [Atom new];

The new method invokes a class’s default init method; it does not invoke a custom init method.

NSProxy

The NSProxy class is an abstract root class used to implement the proxy pattern. It implements a minimal set of methods, thereby enabling almost all messages sent to it being captured and proxied to the target subject. NSProxy implements the methods declared by the NSObject protocol and declares two methods that must be implemented by subclasses:

- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

Note   An abstract class is defined as a class that cannot be directly instantiated; it may have either no implementation or an incomplete implementation. It may also have methods that are required to be implemented. Objective-C does not have language-level support for abstract classes; by convention, you specify an abstract class in Objective-C as one with no initializer and one or more methods that require implementation. Hence, a concrete subclass for an abstract class (e.g., NSProxy) must implement the unimplemented methods and at least one initializer (i.e., one init method).

Additionally, an NSProxy subclass (i.e., a concrete subclass) should declare and implement at least one init method to conform to Objective-C conventions for object creation and initialization. The Foundation Framework includes several concrete subclasses of NSProxy:

  • NSDistantObject: Defines proxies for objects in other applications or threads.
  • NSProtocolChecker: Defines an object that restricts the messages that can be sent to another object.

In Chapter 9, you implemented an NSProxy concrete subclass, AspectProxy, to provide cross-cutting (AOP) functionality around a proxied object. These examples illustrate just a few of the many uses for the NSProxy class.

Strings

The Foundation Framework includes a set of APIs used to manipulate character strings. The operations supported by these classes include:

  • Creating, converting, and formatting strings
  • Reading and writing strings to/from a file or resource
  • String query, sorting, and comparison

In Objective-C a string is represented as an object. This means that strings can be used wherever other objects can be used (in collections, etc.). Each string object is composed of an array of Unicode (i.e., text) characters. The Foundation Framework NSString and NSMutableString classes provide the APIs for string objects. The classes NSAttributedString and NSMutableAttributedString manage strings that have associated attributes (e.g., font, paragraph style, foreground color, etc.). The attributes are identified by name and stored in a Foundation Framework NSDictionary object.

Note   NSString and NSMutableString are members of the NSString class cluster. The class cluster design pattern is used extensively in the Foundation Framework for grouping a number of related classes with a common base interface. Likewise, NSAttributedString and NSMutableAttributedString are members of the NSAttributeString class cluster. In the case of these two class clusters, the mutable class of each pair declares additional methods that allow their (string) contents to be modified.

This family of classes supports the creation of immutable and mutable string objects, attributed strings, and Unicode characters.

NSString

NSString and NSMutableString provide the APIs for Objective-C objects that manage strings. The NSString class manages immutable strings, strings that are defined when they are created and, subsequently, can’t be changed. NSMutableString is the mutable (its contents can be edited) subclass of NSString.

NSMutableString adds methods above those defined by its superclass (NSString) to create and initialize a (mutable) string, and to modify a string.

Creation and Initialization

The NSString class defines numerous methods for creating and initializing strings. The NSString init method returns an initialized NSString object with no characters. The NSString class also defines numerous initializers with parameters. These methods all begin with init and enable you to initialize an NSString object with characters, a byte buffer, contents of a file, contents of a URL, a C string, a UTF8 string, and so forth.

Scanning Values

The NSString class contains numerous methods for retrieving a primitive value from a string object. These methods support basic primitives (i.e., int, float, etc.) and the Foundation Framework NSInteger type. These methods follow a naming convention whereby the return type forms the prefix of the method name. The corresponding method signatures are shown in Listing 10-2.

Listing 10-2.  NSString Methods for Retrieving Primitive Values

- (int) intValue;
- (float) floatValue;
- (double) doubleValue;
- (long long) longLongValue;
- (bool) boolValue;
- (NSInteger) integerValue;

The following example returns a result of type int assigned to the variable myValue for the string "17".

int myValue = [@"17" intValue];

Each of these methods returns a value of 0 if the string doesn’t begin with a valid decimal text representation of a number. Also note that these methods don’t support localization. The Foundation Framework NSScanner class provides additional functionality (including localization) for reading and converting NSString objects into numeric and string values. The following code fragment uses the NSScanner class to set the variable myValue (of type int) for the string "17".

NSScanner *scanner = [NSScanner scannerWithString:@"17"];
BOOL success = [scanner scanInt:&myValue];

The NSScanner scanInt: method returns a BOOL value of YES if the scanned string is numeric; if it returns NO, then the value stored in the variable myValue is not valid.

String Search and Comparison

The NSString class includes several methods to search for a substring within a string object. The rangeOfString: methods each return a range that identifies the first occurrence of an input string within the receiver object. The returned value is an NSRange instance, a Foundation Framework data type used to describe a portion of a series. NSRange is defined as a structure with two elements:

  • location: An NSUInteger that specifies the start of the range.
  • length: An NSUInteger that specifies the length of the range.

The following code fragment returns an NSRange instance assigned to the variable worldRange that identifies the first occurrence of the string "World" within the string "Hello, World!".

NSString *greeting = @"Hello, World!";
NSRange worldRange = [greeting rangeWithString:@"World"];

In the preceding example, the elements of worldRange have the values six (location) and 5 (length). Several of the rangeOfString: methods provide additional parameters that enable you to specify string comparison options, the range within the receiver object to search, and the locale to use for the search.

The NSString rangeOfCharacterFromSet: methods also perform range-based searches. They differ from the rangeOfString: methods in that they return a range that specifies the location (in the receiver string) of the first character found from a given character set. The character set input parameter is of type NSCharacterSet, a set of (Unicode-compliant) characters. The following code fragment returns an NSRange instance that identifies the first occurrence of a punctuation symbol (e.g., period, exclamation point, etc.) within the string "Hello, World!".

NSCharacterSet *chars = [NSCharacterSet punctuationCharacterSet];
NSRange charRange = [@"Hello, World!" rangeOfCharacterFromSet:chars];

In the preceding example, the elements of charRange have the values eleven (location) and 1 (length). As with the rangeOfString: methods, the rangeOfCharacterFromSet: methods provide additional parameters that enable you to specify string comparison options, and the range within the receiver object to search.

The NSString stringByReplacingOccurrencesOfString:withString: methods create a new string from an existing string, with all occurrences of a target (input) string in the receiver replaced by another (input) string. The following code fragment takes an initial string, "Hello, World!", and returns a new string, "Hello, Earthlings!", using this method.

NSString *greeting = @"Hello, World!";
NSString *newGreeting = [greeting stringByReplacingOccurrencesOfString:@"World!"
                         withString:@"Earthlings!"];

The NSString class contains several methods to compare a string to another string. The compare: methods return an NSComparisonResult instance, a Foundation Framework data type used to indicate how the items in a comparison are ordered a portion of a series. NSComparisonResult is defined as an enum with three constants:

  • NSOrderedAscending: The left operand is less than the right.
  • NSOrderedSame: The operands are equal.
  • NSOrderedDescending: The left operand is greater than the right.

The following statement returns an NSComparisonResult assigned to the variable order that identifies the result of the ordered comparison between the strings "cat" and "dog".

NSComparisonResult order = [@"cat" compare:@"dog"];

The result of this comparison is NSOrderedAscending, indicating that the word cat is alphabetically ordered before the word dog. NSString contains additional comparison methods that enable you to perform localized comparisons, case insensitive comparisons, and other options.

String I/O

NSString includes methods for both reading and writing a string to/from a file or a URL. The writeToFile:atomically:encoding:error: method writes a string to a file at the specified path. This method also specifies the encoding to use if the file is written atomically (to prevent the file from being corrupted if the system crashes while the file is being written), and an error object that describes the problem if an error occurs while writing the file. The method returns YES if the string is written to the file successfully. The writeToURL:atomically:encoding:error: method writes a string to a given URL. The NSString stringWithContentsOfFile:, stringWithContentsOfURL:, initWithContentsOfFile:, and initWithContentsOfURL: methods create and initialize a string from a file or URL.

Introspection

The NSString class includes numerous methods for obtaining information about an NSString object. The following statement uses the NSString length method to retrieve the number of characters in the string "Hello, World!".

int len = [@"Hello, World!" length];

The following statement uses the NSString hasPrefix: method to return a Boolean value indicating whether the "Hello, World!" string has a prefix of "Hello".

BOOL hasPrefix = [@"Hello, World!" hasPrefix:@"Hello"];

Modifying a String

NSMutableString adds several methods to those provided by NSString for modifying a string. These methods enable you to append a string or a format string, to insert or delete characters in a string, to replace characters or a string within a string, or to set a string to a new value. The following code fragment creates a mutable string named "Hello" and then appends the string, "World!" to it.

NSMutableString *mgreet = [@"Hello" mutableCopy];
[mgreet appendString:@", World!"];

NSAttributedString

NSAttributedString and NSMutableAttributedString provide the APIs for Objective-C objects that manage strings and associated sets of attributes. The NSAttributedString class manages immutable strings, while the NSMutableAttributedString class manages mutable strings.

The methods provided for the NSAttributedString class enable the creation and initialization of strings, retrieval of string and attribute information, and enumerating over attributes in a string using a block object. The initWithString:attributes: method initializes an NSAttributeString instance with attributes, where the attributes are provided in an NSDictionary instance. The following code fragment creates and initializes an NSAttributedString with the string "Hello" and a single attribute (locale = en-US).

NSDictionary *attrs = @{@"locale":@"en-US"};
NSAttributedString *greeting = [[NSAttributedString alloc] initWithString:@"Hello"
                                                               attributes:attrs];

The next statement retrieves the value of the attribute (using the key "locale") from the attribute string and also sets the range of the attribute to the variable of type NSRange named range.

NSRange range;
id value = [greeting attribute:@"locale" atIndex:0 effectiveRange:&range];

NSString Literals

Objective-C provides language-level support for creating NSString literals using the @ symbol followed by a text string enclosed in double-quotes. The following statement creates an NSString object named book using an NSString literal.

NSString *book = @"Pro Objective-C";

NSString literals are compile-time constants. They are allocated at compile time and exist for the lifetime of the program.

Format Strings

The NSString class includes several methods for formatting string objects using a format string that is composed of ordinary text characters and zero or more format specifiers. A format specifier is a specification for converting an argument in a format string to a character string. Each format specifier begins with a % character that specifies a placeholder for an argument value, immediately followed by a character sequence that indicates the type of the argument. The list of format specifiers supported by the NSString formatting methods include those defined by the IEEE printf specification along with the format specifier '%@', which is used to format an Objective-C object. For example, the format string @"%d" expects an argument of integer type to be substituted for the format string. The NSString stringWithFormat: method and other related methods create and initialize NSString objects using format strings. The syntax for the stringWithFormat method is

+ (id)stringWithFormat:(NSString *)format, ...

Where format is the format string and ... specifies the comma-separated list of argument(s) to substitute into the format. The following example creates an NSString object assigned to the variable magicNumber with the text "Your number is 17".

NSString *magicNumber = [NSString stringWithFormat: @"Your number is %d", 17];

In this example the format string, @"Your number is %d", contains ordinary text and a single format specifier, %d, that is substituted for the argument 17. The next example creates a string formatted using the NSString object magicNumber.

NSString *description = [NSString stringWithFormat:
                         @"Description is %@", magicNumber];

The %@ format specifier substitutes the string returned by invoking either the descriptionWithLocale: (if available) or description method on the object.

The Foundation Framework includes several classes (NSFormatter, NSDateFormatter, NSNumberFormatter) that provide additional functionality for interpreting and creating NSString objects that represent other values.

Value Objects

The Foundation Framework value object classes implement object-oriented wrappers for primitive data types, along with general-purpose system information, tools, and locale support. The NSCalendar, NSDate, NSCalendarDate, NSDateComponents, and NSTimeZone classes provide support for date and time programming and formatting. The NSValue, NSNumber, NSDecimalNumber, and NSDecimalNumberHandler classes provide object-oriented wrappers for primitive data types, which can then be manipulated and/or added to collection objects. The NSData, NSMutableData, and NSPurgeableData classes provide object-oriented wrappers for byte buffers. NSValueTransformer is used to transform values from one representation to another. NSNull is a singleton object used to represent null values in collection objects that don’t allow nil values. NSLocale provides support for locales, a collection of information used to adapt software for a specific region or language. NSCache provides an in-memory system cache for the temporary storage of objects that are expensive to re-create.

NSValue

The NSValue class is a container for a single data item. It can hold both C and Objective-C data types (including primitives) of constant length and is typically used to allow an item to be stored in a collection object (NSArray, NSSet, etc.), because these require their elements to be objects. The code fragment in Listing 10-3 creates an NSValue instance from a value of type int.

Listing 10-3.  Creating an NSValue Instance

int ten = 10;
int *tenPtr = &ten;
NSValue *myInt = [NSValue value:&tenPtr withObjCType:@encode(int *)];

Note that the type is specified using an @encode directive. This value can now be stored in a collection object. The following statement retrieves the int value of the NSValue object and assigns this value to the variable result.

int result = *(int *)[myInt pointerValue];

NSNumber

The NSNumber class is a subclass of NSValue that functions as a container for primitive (scalar) types. It defines a set of methods for creating and accessing number objects as primitive types: signed/unsigned char, int, short int, long int, long long int, NSInteger, float, double, or BOOL types. NSNumber includes numerous class factory methods (whose names all begin with numberWith...) for creating and initializing an NSNumber with an input parameter of the specified primitive type. The following statement uses the numberWithDouble: method to create an NSNumber instance of type double and assign it to a variable named degrees2Radians.

NSNumber *degrees2Radians = [NSNumber numberWithDouble:(3.1415/180.0)];

NSNumber also includes initialization methods (whose names all begin with initWith...) to initialize an allocated NSNumber object with the input parameter value. The corresponding NSNumber ...Value methods (one for each of the supported types) can be used to retrieve a primitive value from an NSNumber object, for example:

double d2r = [degrees2Radians doubleValue];

NSNumber also includes a stringValue method to get the string representation of an NSNumber instance.

NSDecimalNumber

NSDecimalNumber is a subclass of NSNumber that is used to perform decimal arithmetic. It includes methods for creating and initializing decimal numbers, and methods for performing standard arithmetic operations (addition, subtraction, multiplication, division, etc.). It is especially useful for performing these operations on numbers where rounding errors can be significant (for example, with currency). Listing 10-4 adds two NSDecimalNumber objects and assigns the result to an NSDecimalNumber object named sum.

Listing 10-4.  Adding Two Numbers Using NSDecimalNumber

NSDecimalNumber *num1 = [NSDecimalNumber decimalNumberWithString:@"2.56"];
NSDecimalNumber *num2 = [NSDecimalNumber decimalNumberWithString:@"7.78"];
NSDecimalNumber *sum = [num1 decimalNumberByAdding:num2];

The NSDecimalNumber methods that perform arithmetic operations include parameters that can be used to specify how calculation errors and rounding are handled.

NSNumber Literals

Objective-C provides language-level support for creating NSNumber literals. Any character, numeric, or Boolean literal that is prefixed with an @ character evaluates to an NSNumber object initialized to that value. The following statements are equivalent:

NSNumber *num = [NSNumber numberWithInt:17];
NSNumber *num = @17;

NSNumber literals are created from scalar values, not expressions. In addition, NSNumber literals are evaluated at runtime; they are not compile-time constants and thus cannot be used to initialize static variables. In essence, the literal @17 is actually shorthand for the expression [NSNumber numberWithInt:17], an object message that is evaluated at runtime. More information on NSNumber literals is provided in Chapter 16, which explores Objective-C literals in depth.

Date and Time Support

The NSCalendar, NSDate, NSCalendarDate, NSDateComponents, and NSTimeZone classes provide support for date and time programming and formatting. An NSDate instance represents an absolute timestamp. The following statement creates a date that represents the current time.

NSDate *now = [[NSDate alloc] init];

The following statements compare two dates and return an NSComparisonResult that indicates whether the input date is later, the same, or earlier than the receiver’s dates.

NSTimeInterval secondsPerDay = 24 * 60 * 60;
NSDate *tomorrow = [now dateByAddingTimeInterval:secondsPerDay];
NSComparisonResult *result = [now compare:tomorrow];

The NSCalendar class encapsulates calendar information used to organize periods of time. It provides an implementation for several different calendars, including the Buddhist, Gregorian, Hebrew, Islamic, and Japanese calendars. The following statement returns a calendar for the current user’s chosen locale.

NSCalendar *currentCalendar = [NSCalendar currentCalendar];

The following statement creates a Gregorian calendar.

NSCalendar *gregorianCalendar = [[NSCalendar alloc]
                                initWithCalendarIdentifier:NSGregorianCalendar];

NSCalendar provides methods for retrieving the component elements of a date in a calendar, represented as NSDateComponents objects.

The NSDateComponents class represents the component elements of a date/time. It is used to set/get these elements, and also specify a time interval. The following statements retrieve date components from a current calendar object with monthly calendar units.

NSDate *date = [NSDate date];
NSDateComponents *components = [currentCalendar components:NSMonthCalendarUnit
                                                    fromDate:date];

NSCache

In computer programming, a cache is a mechanism that stores data so that future requests for the same data can be retrieved more quickly. They are commonly used to store objects that are expensive to re-create. The Foundation Framework NSCache class provides an in-memory system cache for the temporary storage of objects that are expensive to re-create. In addition to managing cache values, the class includes methods for managing the cache size, managing discarded objects, and managing the cache delegate. A cache delegate conforms to the NSCacheDelegate protocol, and is sent messages when an object is about to be evicted or removed from the cache. An NSCache instance stores key-value pairs, similar to an NSDictionary (to be discussed later in this chapter). It differs in that it provides autoremoval policies, and thus manages memory utilization. The following code fragment creates an NSCache instance, sets the number of objects the cache can hold, and then adds an object to the cache.

NSCache *cache = [[NSCache alloc] init];
[cache setCountLimit:500];
[cache setObject:@"Hello, World!" forKey:@"greeting"];

Collections

The Foundation Framework collections classes manage collections of objects. Most collection classes have both an immutable and a mutable version. NSArray and NSMutableArray manage arrays, ordered collections of objects that can be of any type; the elements of an NSArray do not have to be of the same type. NSDictionary and NSMutableDictionary are used for groups of key-value pairs. NSSet, NSMutableSet, and NSCountedSet are used to manage unordered collections of objects. The NSEnumerator and NSDirectoryEnumerator classes enumerate collections of other objects, such as arrays and dictionaries. NSIndexSet and NSMutableIndexSet manage collections of index sets (collections of unique unsigned integers used to store indexes into another data structure). NSHashTable, NSMapTable, and NSPointerArray are mutable collections that support weak relationships when using the garbage collector.

The NSHashTable, NSMapTable, and NSPointerArray classes are available for use on the Apple OS X platform only (i.e., these classes are not available for the iOS platform).

NSArray

NSArray and NSMutableArray manage ordered collections of objects that do not have to be of the same type. NSArray is immutable (the objects assigned to the array at initialization cannot be removed, although there contents can be changed). NSMutableArray allows adding or removing objects in a collection. The operations supported by NSArray include array creation and initialization, query (obtaining information about the array or retrieving its elements), finding an object in an array, object messaging to array elements, comparing arrays, and sorting an array. Many NSArray and NSMutableArray operations are executed in constant time (accessing an element, adding/removing on ends, replacing an element), whereas inserting an element in the middle of an NSMutableArray takes linear time. The following statement uses the NSArray arrayWithObjects: convenience constructor to create an NSArray object assigned to the variable myArray initialized with NSNumber literals.

NSArray *myArray = [NSArray arrayWithObjects:@1, @2, nil];

Notice that the arrayWithObjects: method requires parameters with a comma-separated list of objects ending with nil. The next statement retrieves the first element of this NSArray object using the NSArray indexOfObject: method.

id num0 = [myArray objectAtIndex:0];

The following statement returns the index of the NSNumber object (with a value of 2) in the preceding NSArray object.

NSUInteger index = [myArray indexOfObject:@2];

NSArray also includes the following methods to persist the contents of an array to a property list and initialize an NSArray object from a property list:

- writeToFile:atomically:
- writeToURL:atomically:
- initWithContentsOfFile:
- initWithContentsOfURL:

When persisting an array (via the writeTo... methods), its contents must all be property list objects (i.e., NSString, NSData, NSDate, NSNumber, NSArray, NSDictionary objects).

NSArray Literals

Objective-C provides language-level support for creating NSArray literals. The array is defined by a comma-separated list of objects between square brackets, prefixed by an @ character. Unlike the NSArray arrayWithObjects: and initWithObjects: methods, the list of objects used to define an NSArray literal is not required to end with a nil. The following statements are equivalent:

NSArray *myArray = [NSArray arrayWithObjects:@1, @2, nil];
NSArray *myArray = @[@1, @2];

As with NSNumber literals, NSArray literals are not compile-time constants; they are evaluated at runtime.

NSPointerArray

NSPointerArray is a mutable collection similar to NSMutableArray that can hold arbitrary pointers and NULL values. It also allows you to manage the collection by setting the count for the array, such that if the number of elements in the collection is less than the count, then the collection is padded with NULL values; or if the number of elements in the collection is greater than the count, then the elements in the collection above the count value are removed.

NSDictionary

The NSDictionary and NSMutableDictionary classes manage collections of key/value (object) pairs. Within a collection, the value of a key is unique (i.e., it must be an object that adopts the NSCopying protocol and implements the hash and isEqual: methods). The operations supported by these classes include object creation and initialization, query, finding objects in the collection, filtering, comparing, and sorting the collection. The sorting options include sorting with selectors (using the keySortedByValueUsingSelector: method), and sorting with blocks (using the keySortedByValueUsingComparator: method). For keys with good hash functions (for example, NSString), NSDictionary operations take constant time (accessing, setting, removing an element from an NSDictionary or NSMutableDictionary). The code fragment shown in Listing 10-5 creates and initializes an NSDictionary object with two elements.

Listing 10-5.  Creating and Initializing an NSDictionary Object

NSArray *objects = @[@1, @2];
NSArray *keys = @[@"one", @"two"];
NSDictionary *myDi = [NSDictionary dictionaryWithObjects:objects];
                       withKeys:keys];

The next statement retrieves the value from the preceding NSDictionary object that has the key "one".

id value = [myDi objectForKey:@"one"];

As with NSArray, NSDictionary includes methods to persist the contents of a dictionary to a property list and initialize an NSDictionary object from a property list:

- writeToFile:atomically:
- writeToURL:atomically:
- initWithContentsOfFile:
- initWithContentsOfURL:

When persisting a dictionary (via the writeTo... methods), its contents must all be property list objects (NSString, NSData, NSDate, NSNumber, NSArray, and NSDictionary objects).

NSDictionary Literals

Objective-C provides language-level support for creating NSDictionary literals. The dictionary is defined by a comma-separated list of key-value pairs between curly braces, prefixed by an @ character. In each key-value pair, a colon separates the key and value. The following statements are equivalent:

NSArray *objects = @[@1, @2];
NSArray *keys = @[@"one", @"two"];
NSDictionary *myDi = [NSDictionary dictionaryWithObjects:objects];

NSDictionary *myDi = @{@"one":@1, @"two":@2};

As with NSNumber literals, NSDictionary literals are not compile-time constants; they are evaluated at runtime.

NSMapTable

NSPointerArray is a mutable collection similar to NSDictionary that provides additional storage options. Specifically, it can store arbitrary pointers. It can also store weakly referenced keys and/or values.

NSSet

NSSet and NSMutableSet manage unordered collections of objects that do not have to be of the same type. The objects stored in an NSSet are unique. The operations supported by NSSet include creation and initialization, finding an object in a set, comparing, and sorting (using the NSSet sortedArrayUsingDescriptors: method). If the objects in the set have a good hash function, accessing an element, setting an element, and removing an element all take constant time. With a poor hash function (one that causes frequent hash collisions), these operations take up linear time.

Sets, excluding NSCountedSets, ensure that no object is represented more than once, and there is no net effect for adding an object more than once. The following statement uses the NSSet setWithObjects: convenience constructor to create an NSSet object assigned to the variable mySet initialized with NSNumber literals.

NSSet *mySet = [NSSet setWithObjects:@1, @2, nil];

NSCountedSet

NSCountedSet is a mutable set that allows an object to be added multiple times (i.e., its elements aren’t required to be distinct). Each distinct object has an associated counter. An NSSet object keeps track of the number of times each distinct object is inserted and requires a corresponding object(s) to be removed the same number of times.

NSHashTable

NSHashTable is a mutable collection similar to NSSet that provides different options. Specifically, it can store arbitrary pointers. It can also store weakly referenced keys and/or values.

NSPointerFunctions

The NSPointerFunctions class defines functions for managing pointer functions. An NSHashTable , NSMapTable , or NSPointerArray object typically uses an NSPointerFunctions instance to define behavior for the pointers it manages.

XML Processing

The Foundation Framework XML processing classes support general-purpose XML document management and parsing functionality. The classes logically represent an XML document as a hierarchical tree structure and support the query and manipulation of XML document nodes. These classes support several XML-related technologies and standards, such as XQuery, XPath, XInclude, XSLT, DTD, and XHTML.

Classes NSXMLDTD and NSXMLDTDNode are used for creating and modifying XML Document Type Definitions (DTDs). NSXMLDocument, NSXMLNode, and NSXMLElement are used for tree-based processing of XML documents. Instances of NSXMLParser are used to parse XML documents in an event-driven manner.

XML DTD Processing

The NSXMLDTD classes (NSXMLDTD and NSXMLDTDNode) represent a Document Type Definition (DTD). They are used for creating and modifying DTDs. The XML DTD processing classes (NSXMLDTD, NSXMLDTDNode) are available for use on the Apple OS X platform only (i.e., these classes are not available for the iOS platform).

Tree-Based XML Processing

The Foundation NSXML classes enable you to create, manipulate, modify, and query XML documents. These classes employ a Document Object Model (DOM) styled, tree-based data model that represents an XML document as a tree of nodes. Each node of the tree corresponds to an XML construct—an Element, an Attribute, Text, a Comment, a Processing Instruction, or a Namespace. An NSXMLDocument object represents an entire XML document as a logical tree structure. The code fragment shown in Listing 10-6 creates an NSXMLDocument for the URL http://www.apress.com/proobjectivec.xml .

Listing 10-6.  Creating an NSXMLDocument Object

NSURL *url = [NSURL URLWithString:@"http://www.apress.com/proobjectivec.xml"];
NSError *err;
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc]
                          initWithContentsOfURL:url
                                        options:NSXMLDocumentValidate
                                          error:&err];

NSXMLNode, the superclass of NSXMLDocument, includes methods for navigating a tree of nodes from an XML document. The following code fragment uses an NSXMLNode method, nextNode, to retrieve the next node in an XML document.

NSXMLNode *node = [xmlDoc nextNode];

NSXMLElement, a subclass of NSXMLNode, represents element nodes in an XML tree structure. It includes methods for managing child elements and attributes of an XML document. The following code fragment gets the NSXMLElement object with the given tag name of "test" and then uses this object to retrieve the child element nodes (an NSArray object) that have the specified name.

NSXMLElement *testElem = [NSXMLNode elementWithName:@"test"];
NSArray *children = [noteElem elementsForName:@"item"];

The XML processing classes (NSXMLDocument, NSXMLNode, NSXMLElement) are available for use on the Apple OS X platform only (i.e., these classes are not available for the iOS platform).

Event-Driven XML Processing

The NSXMLParser class is used to parse XML documents, including DTD documents, in an event-driven manner. An NSXMLParser instance is configured with a delegate, an object that implements certain methods that are invoked on it while the NSXMLParser instance is processing an XML document. The delegate must conform to the NSXMLParserDelegate protocol, thereby enabling it to respond to events (i.e., method invocations) when the parser begins/ends processing the document, processes XML elements and attributes, and so forth. The method shown in Listing 10-7 demonstrates the creation, initialization, and use of an NSXMLParser instance to parse an XML document.

Listing 10-7.  Parsing an XML Document

- (void) parseXMLInfoset:(NSString *)file
{
  NSURL *infoset = [NSURL fileURLWithPath:file];
  NSXMLParser *parser = [[NSXMLParser alloc]
    initWithContentsOfURL:infoset];
  [parser setDelegate:self];
  [parser setShouldResolveExternalEntities:YES];
  [parser parse];
}

As mentioned earlier, a delegate object must conform to the NSXMLParserDelegate protocol to be able to process document parsing events (e.g., begin parsing a document, end parsing a document, start parsing an element, start mapping a namespace prefix, end mapping a namespace prefix) from an NSXMLParser instance. Unlike the NSXML (tree-based XML processing classes), the event-driven XML parser classes enable you to read XML documents but not create or update them.

The NSXMLParser class is available for use on both the Apple OS X and iOS platform. The other XML processing classes mentioned here are only available for use on the OS X platform.

Predicates

This collection of classes provides a general means of specifying queries using predicates and expressions. A predicate is a logical operator that returns either a true or false value and is composed of one or more expressions. Predicates are used to constrain a search for a query or to provide filtering of returned results. The NSExpression class is used to represent expressions in a predicate, and it supports multiple expression types. NSPredicate, NSComparisonPredicate, and NSCompoundPredicate are used to create predicates. The code fragment shown in Listing 10-8 creates and initializes an array, then creates a predicate that searches for elements in the array with a value greater than 1, and then creates a new, filtered array using this predicate.

Listing 10-8.  Creating a Filtered Array Using a Predicate

NSArray *nArray = @[@1, @2];
NSPredicate *pred = [NSPredicate predicateWithFormat: @"SELF > 1"];
NSArray *filteredArray = [nArray filteredArrayUsingPredicate:pred];

Roundup

In this chapter, you began your review of the Foundation Framework, focusing on classes that provide common, general-purpose functionality required for most Objective-C programs. You should now be familiar with Foundation Framework classes that provide the following functionality:

  • Root classes
  • Working with strings
  • Numbers and value objects
  • Collections
  • XML processing
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.188.244