Object subscripting is a recent addition to the Objective-C language that enables Objective-C objects to be used with the C subscripting operator ([]). It provides a clean, concise syntax for getting and setting the elements of a Foundation Framework array and dictionary (e.g., NSArray andNSDictionary). In addition, the subscripting operators are generic, and thus enable the corresponding methods to be implemented by any class to provide custom subscripting.
NSArray Subscripting
When applied to NSArray and NSMutableArray objects, the subscript operand has an integral type.NSArray supports getting the elements of an array using the subscript operand. The example shown in Listing 16-12 creates an NSArray literal and then retrieves an element from the resultant array using subscripting.
Listing 16-12. Retrieving an NSArray Element Using Subscripting
NSArray *words = @[@"Hello", @"World"];
NSString *word = words[0];
NSMutableArray supports both getting and setting the elements of an array using the subscript operand. Listing 16-13 creates a mutable array from an NSArray literal, and then sets an element of the array to a new value.
Listing 16-13. Setting an NSMutableArray Element Using Subscripting
NSMutableArray *words = [@[@"Hello", @"World"] mutableCopy];
words[1] = @"Earthlings";
The NSArray and NSMutableArray classes use the subscript operand (i.e., an index) to access the appropriate element from its collection. The subscripting operator does not allow you to add elements to a mutable array; it only allows you to replace existing elements. For either NSArray orNSMutableArray instances, if the subscripting operand is outside of the array bounds, anNSRangeException is thrown. In addition, when setting an NSMutableArray element using subscripting, the object the array element is being set to must not be nil.
When the subscript operand is applied on an NSArray or NSMutableArray object, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. For read (i.e., get) operations, the compiler translates this into an expression using the NSArray method objectAtIndexedSubscript:. In effect, the following two expressions are equivalent:
NSString *word = words[0]
NSString *word = [words objectAtIndexedSubscript:1]
For write (i.e., set) operations, the compiler translates this into an expression that uses the NSMutableArray method setObject:atIndexedSubscript:. In effect, the following two expressions are equivalent:
words[1] = @"Earthlings";
[words setObject:@"Earthlings" atIndexedSubscript:1];
The NSArray method objectAtIndexedSubscript: takes an NSUInteger (e.g., an unsigned integer) as its input parameter and returns a value of some Objective-C object pointer type. The NSMutableArray method setObject:atIndexedSubscript: takes an Objective-C pointer type as its first parameter and an NSUInteger as its second parameter.
NSDictionary Subscripting
When applied to NSDictionary and NSMutableDictionary objects, the subscript operand has an Objective-C pointer type. NSDictionary supports getting the elements of a dictionary using the subscript operand. The example shown in Listing 16-14 creates an NSDictionary literal, and then retrieves an element from the resultant array using subscripting.
Listing 16-14. Retrieving an NSDictionary Element Using Subscripting
NSDictionary *order1 = @{@1111:@"1 Cheeseburger",
@1112:@"2 Hot dogs"};
NSString *order = order1[@1111];
NSMutableDictionary supports both getting and setting the elements of an array using the subscript operand. Listing 16-15 creates a mutable dictionary from an NSDictionary literal, and then sets an element of the array to a new value.
Listing 16-15. Setting an NSMutableDictionary Element Using Subscripting
NSMutableDictionary *order1 = [@{@1111:@"1 Cheeseburger",
@1112:@"2 Hot dogs"} mutableCopy];
order1[@1112] = @"1 Cheese pizza";
The NSDictionary and NSMutableDictionary classes use the subscript operand (i.e., a key) to access the appropriate element from its collection. The subscripting operator does not allow you to add elements to a mutable array; it only allows you to replace existing elements. For NSDictionaryor NSMutableDictionary instances, attempting to retrieve an element via subscripting returns nil if there is no value associated with the input key. When setting an NSMutableDictionary element using subscripting, the method raises an NSInvalidArgument exception if the key or object is nil.
When the subscript operand is applied on an NSDictionary or NSMutableDictionary object, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. For read (i.e., get) operations, the compiler translates this into an expression using the NSDictionary method objectForKeyedSubscript:. In effect, the following two expressions are equivalent:
NSString *order = order1[@1111];
NSString *order = [order1 objectForKeyedSubscript:@1111];
For write (i.e., set) operations, the compiler translates this into an expression that uses the NSMutableDictionary method setObject:forKeyedSubscript:. In effect, the following two expressions are equivalent:
order[@1111] = @"1 Cheeseburger";
[order setObject:@"1 Cheeseburger" forKeyedSubscript:@1111];
The NSDictionary method objectForKeyedSubscript: takes an Objective-C pointer type that conforms to the NSCopying protocol as its input parameter and returns a value of some Objective-C object pointer type. The NSMutableDictionary method setObject:forKeyedSubscript: takes an Objective-C pointer type as its first parameter and an Objective-C pointer type that conforms to theNSCopying protocol as its second parameter.
As with Objective-C Literals, the object subscripting operations are evaluated at runtime; as such, they are not compile-time constants and cannot be used to initialize static or global variables.
Custom Subscripting
As noted earlier, the object subscripting operators support any type of Objective-C object. The compiler translates these operators into message selectors, and your code implements one or more of the corresponding methods to support object subscripting. In effect, there are two types of subscript expressions: array-style and dictionary-style. You were introduced to this with the NSArray andNSDictionary subscripting operations presented earlier. In sum, array-style subscript expressions use integer typed subscripts, and dictionary-style subscript expressions use Objective-C object pointer typed subscripts (i.e., a key). Each type of subscript expression is mapped to a message send operation using a predefined selector.
The instance methods for array-style subscripting are
- (id)objectAtIndexedSubscript:(NSUInteger)index
- (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index
The objectAtIndexedSubscript: method retrieves the value at the specified index, whereas thesetObject:atIndexedSubscript: method sets the value at the specified index. As an example, given a class named Hello that supports array-style subscripting, an array-style subscript expression is used to return a value in the following assignment statement.
id value = helloObject[2]; // helloObject is a Hello class instance
In this case (i.e., retrieving a value for an associated index), the subscript expression (helloObject[2]) is translated by the compiler into a message send with the selectorobjectAtIndexedSubscript:, and is thus equivalent to the statement
id value = [helloObject objectAtIndexedSubscript:2];
In the next example, an array-style subscript expression is used to set a value in an assignment statement.
helloObject[2] = @"Howdy";
When setting a value via an array-style subscript expression, the expression (in this casehelloObject[2]) is translated by the compiler into a message send with the selectorsetObject:atIndexedSubscript:, and is thus equivalent to the statement
[helloObject setObject:@"Howdy" atIndexedSubscript:2];
The message-send operations are type-checked and performed just like explicit Objective-C message sends. The implementing class determines the meaning of the index.
The instance methods for dictionary-style subscripting are
- (id)objectForKeyedSubscript:(id)key
- (void)setObject:(id)anObject forKeyedSubscript:(id<NSCopying>)key
These methods are analogous to the array-style subscripting methods, using a key (of type id—i.e., an object pointer) instead of an index to get or set the associated value. Given a class named Orderthat supports dictionary-style subscripting, a dictionary-style subscript expression is used to return a value in the following statement.
id item = orderObject[@"1234"]; // orderObject is an Order class instance
In this case, the subscript expression (orderObject[@"1234"]) is translated by the compiler into a message send with the selector objectForKeyedSubscript:, and is thus equivalent to the statement
id item = [orderObject objectForKeyedSubscript:@"1234"];
Conversely, a dictionary-style subscript expression is used to set a value in the following assignment statement.
orderObject[@"1234"] = @"Cheeseburger";
In this case, the subscript expression (orderObject[@"1234"]) is translated by the compiler into a message send with the selector setObject:forKeyedSubscript:, and is thus equivalent to the statement.
[orderObject setObject:@"Cheeseburger" forKeyedSubscript:@"1234"];
As shown in these examples, the custom subscripting operations should be used to get and set the elements of an object, and not for other purposes (e.g., appending or deleting objects, etc.). This enables the syntax to remain consistent with its intent, and thus identical to that employed for the Foundation Framework array and dictionary subscript operations.
本文深入探讨了 Objective-C 中的 ObjectSubscripting 操作,包括 NSArray 和 NSDictionary 的用法,以及如何实现自定义的 subscripting 功能。

被折叠的 条评论
为什么被折叠?



