Traditionally,
NSString *constkFirstNameKey =@"firstName";
NSString *constkLastNameKey =@"lastName";
NSMutableDictionary *dictionary= [[NSMutableDictionaryalloc] init];
[dictionary setValue:@"Tim"forKey:kFirstNameKey];
[dictionary setValue:@"Cook"forKey:kLastNameKey];
__unused NSString *firstName= [dictionaryvalueForKey:kFirstNameKey];
__unused NSString *lastName= [dictionaryvalueForKey:kLastNameKey];
But with all the advances in the LLVM compiler, this code can now be shortened to this:
NSString *constkFirstNameKey =@"firstName";
NSString *constkLastNameKey =@"lastName";
NSDictionary *dictionary= @{
kFirstNameKey : @"Tim",
kLastNameKey : @"Cook",
};
__unused NSString *firstName= dictionary[kFirstNameKey];
__unused NSString *lastName= dictionary[kLastNameKey];
Subscripting by key
With this, you can set the value for a specific key inside an object, just like you would in a dictionary. You can also access/read-from values inside the object by providing the key.
Subscripting by index
As with arrays, you can set/get values inside the object by providing an index to that object. This makes sense for array-like classes where the elements lie in a natural order that can be represented by an index.
A:
For the first example, we are going to look at subscripting by key. To do this, we are going to create a class named Person with a firstName and a lastName. Then we are going to allow the programmer to change the first and last names by simply providing the keys to those properties.
In order to support subscripting by key on your own classes, you must implement the following two methods on your classand put the method signatures in your class’s header file; otherwise, the compiler won’t know that your class supports subscripting by key.
#import <Foundation/Foundation.h>
/* We will use these as the keys to our firstName and lastName
properties so that if our firstName and lastName properties' names
change in the future in the implementation, we won't break anything
and our class will still work, as we can simply change the value of
these constants inside our implementation file */
extern NSString *constkFirstNameKey;
extern NSString *constkLastNameKey;
@interfacePerson : NSObject
@property (nonatomic,copy) NSString *firstName;
@property (nonatomic,copy) NSString *lastName;
- (id)objectForKeyedSubscript:(id<NSCopying>)paramKey;
- (void)setObject:(id)paramObjectforKeyedSubscript:(id<NSCopying>)paramKey;
@end
//
The objectForKeyedSubscript: method will be called on your class whenever the programmer provides a key and wants to read the value of that key in your class.
To complement this method, the setObject:forKeyedSubscript: method will be called on your class whenever the programmer wants to set the value for a specified key.
#import "Person.h"
NSString *constkFirstNameKey =@"firstName";
NSString *constkLastNameKey =@"lastName";
@implementation Person
- (id)objectForKeyedSubscript:(id<NSCopying>)paramKey{
NSObject<NSCopying>*keyAsObject = (NSObject<NSCopying>*)paramKey;
if ([keyAsObjectisKindOfClass:[NSStringclass]]){
NSString *keyAsString= (NSString*)keyAsObject;
if ([keyAsStringisEqualToString:kFirstNameKey] ||
[keyAsString isEqualToString:kLastNameKey]){
return [selfvalueForKey:keyAsString];
}
}
return nil;
}
- (void)setObject:(id)paramObjectforKeyedSubscript:(id<NSCopying>)paramKey{
NSObject<NSCopying>*keyAsObject = (NSObject<NSCopying>*)paramKey;
if ([keyAsObjectisKindOfClass:[NSStringclass]]){
NSString *keyAsString= (NSString*)keyAsObject;
if ([keyAsStringisEqualToString:kFirstNameKey] ||
[keyAsString isEqualToString:kLastNameKey]){
[self setValue:paramObjectforKey:keyAsString];
}
}
}
@end
// elsewhere
Person *person= [Personnew];
person[kFirstNameKey] = @"Tim";
person[kLastNameKey] = @"Cook";
__unused NSString *firstName= person[kFirstNameKey];
__unused NSString *lastName= person[kLastNameKey];
==
Person *person= [Personnew];
person.firstName =@"Tim";
person.lastName =@"Cook";
__unused NSString *firstName= person.firstName;
__unused NSString *lastName= person.lastName;
B:
// headers file
- (id)objectAtIndexedSubscript:(NSUInteger)paramIndex;
- (void)setObject:(id)paramObjectatIndexedSubscript:(NSUInteger)paramIndex;
- (id)objectAtIndexedSubscript:(NSUInteger)paramIndex{
switch (paramIndex){
case 0:{
return self.firstName;
break;
}
case 1:{
return self.lastName;
break;
}
default:{
[NSException raise:@"Invalid index"format:nil];
}
}
return nil;
}
- (void)setObject:(id)paramObjectatIndexedSubscript:(NSUInteger)paramIndex{
switch (paramIndex){
case 0:{
self.firstName= paramObject;
break;
}
case 1:{
self.lastName= paramObject;
break;
}
default:{
[NSException raise:@"Invalid index"format:nil];
}
}
}
Now we can test out what we’ve written so far, like so:
Person *person= [Personnew];
person[kFirstNameKey] = @"Tim";
person[kLastNameKey] = @"Cook";
NSString *firstNameByKey= person[kFirstNameKey];
NSString *lastNameByKey= person[kLastNameKey];
NSString *firstNameByIndex= person[0];
NSString *lastNameByIndex= person[1];
if ([firstNameByKeyisEqualToString:firstNameByIndex]&&
[lastNameByKey isEqualToString:lastNameByIndex]){
NSLog(@"Success");
} else {
NSLog(@"Something is not right");
}