NSArray,NSDictionary, NSSet 的差異

根據developer.apple.com的“Collections Programming Topics”中的描述:

About Collections

In Cocoa and Cocoa Touch, a collection is a Foundation framework class used for storing and managing groups of objects. Its primary role is to store objects in the form of either an array, a dictionary, or a set.

image: Art/collections_intro_2x.png

These classes ease the task of managing groups of objects. Foundation collections are efficient and used extensively by OS X and iOS.

從上述的描述中,我們可以清楚看到Array是順序的,而NSDictionary的Keys是順序的,values是散列的,而set是散列的並且是唯一的。

而對於NSDictionary中的Key,進一步的描述可見於:

Dictionaries: Collections of Keys and Values

Dictionaries manage pairs of keys and values. A key-value pair within a dictionary is called an entry. Each entry consists of one object that represents the key, and a second object which is that key’s value. Within a dictionary, the keys are unique—that is, no two keys in a single dictionary are equal (as determined by isEqual:). A key can be any object that adopts the NSCopying protocol and implements the hash and isEqual: methods. Figure 1 shows a dictionary which contains information about a hypothetical person. As shown, a value contained in the dictionary can be any object, even another collection.

Figure 1  Example dictionary

Dictionary Fundamentals

An NSDictionary object manages an immutable dictionary—that is, after you create the dictionary, you cannot add, remove or replace keys and values. You can, however, modify individual values themselves (if they support modification), but the keys must not be modified. The mutability of the collection does not affect the mutability of the objects inside the collection. You should use an immutable dictionary if the dictionary rarely changes, or changes wholesale.

An NSMutableDictionary object manages a mutable dictionary, which allows the addition and deletion of entries at any time, automatically allocating memory as needed. You should use a mutable dictionary if the dictionary changes incrementally, or is very large—as large collections take more time to initialize.

You can easily create an instance of one type of dictionary from the other using the initializer initWithDictionary: or the convenience constructordictionaryWithDictionary:.

In general, you instantiate a dictionary by sending one of the dictionary...messages to either the NSDictionary or NSMutableDictionary class. The dictionary...messages return a dictionary containing the keys and values you pass in as arguments. Objects added as values to a dictionary are not copied (unless you pass YES as the argument to initWithDictionary:copyItems:). Rather, a strong reference to the object is added to the dictionary. For information on how a dictionary handles key objects, see “Using Custom Keys.” For more information on copying and memory management, see “Copying Collections.”

Internally, a dictionary uses a hash table to organize its storage and to provide rapid access to a value given the corresponding key. However, the methods defined for dictionaries insulate you from the complexities of working with hash tables, hashing functions, or the hashed value of keys. The methods take keys directly, not in their hashed form.

Note: If the key objects 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 to linear time. Classes such as NSString that are part of Foundation have a good hash function.

Using Mutable Dictionaries

When removing an entry from a mutable dictionary, remember that the dictionary’s strong reference to the key and value objects that make up the entry are discarded. If there are no further strong references to the objects, they’re deallocated.

Adding objects to a mutable dictionary is relatively straightforward. To add a single key-value pair, or to replace the object for a particular key, use the setObject:forKey: instance method, as shown in Listing 1.

Listing 1  Adding objects to a dictionary

NSString *last = @"lastName";
NSString *first = @"firstName";
 
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
        @"Jo", first, @"Smith", last, nil];
NSString *middle = @"middleInitial";
 
[dict setObject:@"M" forKey:MIDDLE];

You can also add entries from another dictionary using the addEntriesFromDictionary: instance method. If both dictionaries contain the same key, the receiver’s previous value object for that key is released and the new object takes its place. For example, after the code in Listing 2 executes, dict would have a value of “Jones” for the key “lastName”.

Listing 2  Adding entries from another dictionary

NSString *last = @"lastName";
NSString *first = @"firstName";
NSString *suffix = @"suffix";
NSString *title = @"title";
 
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
    @"Jo", first, @"Smith", last, nil];
 
NSDictionary *newDict = [NSDictionary dictionaryWithObjectsAndKeys:
    @"Jones", last, @"Hon.", title, @"J.D.", suffix, nil];
 
[dict addEntriesFromDictionary: newDict];

Sorting a Dictionary

NSDictionary provides the method keysSortedByValueUsingSelector:, which returns an array of the dictionary’s keys in the order they would be in if the dictionary were sorted by its values, as illustrated in Listing 3.

Listing 3  Sorting dictionary keys by value

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithInt:63], @"Mathematics",
    [NSNumber numberWithInt:72], @"English",
    [NSNumber numberWithInt:55], @"History",
    [NSNumber numberWithInt:49], @"Geography",
    nil];
 
NSArray *sortedKeysArray =
    [dict keysSortedByValueUsingSelector:@selector(compare:)];
// sortedKeysArray contains: Geography, History, Mathematics, English

You can also use blocks to easily sort a dictionary’s keys based on their corresponding values. The keysSortedByValueUsingComparator: method of NSDictionary allows you to use a block to compare the keys to be sorted into a new array. Listing 4 illustrates sorting with a block.

Listing 4  Blocks ease custom sorting of dictionaries

NSArray *blockSortedKeys = [dict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {
 
     if ([obj1 integerValue] > [obj2 integerValue]) {
          return (NSComparisonResult)NSOrderedDescending;
     }
 
     if ([obj1 integerValue] < [obj2 integerValue]) {
          return (NSComparisonResult)NSOrderedAscending;
     }
     return (NSComparisonResult)NSOrderedSame;
}];

Using Custom Keys

In most cases, Cocoa-provided objects such as NSString objects should be sufficient for use as keys. In some cases, however, it may be necessary to use custom objects as keys in a dictionary. When using custom objects as keys, there are some important points to keep in mind.

Keys must conform to the NSCopying protocol. Methods that add entries to dictionaries—whether as part of initialization (for all dictionaries) or during modification (for mutabledictionaries)— don’t add each key object to the dictionary directly. Instead, they copy each key argument and add the copy to the dictionary. After being copied into the dictionary, the dictionary-owned copies of the keys should not be modified.

Keys must implement the hash and isEqual: methods because a dictionary uses a hash table to organize its storage and to quickly access contained objects. In addition, performance in a dictionary is heavily dependent on the hash function used. With a bad hash function, the decrease in performance can be severe. For more information on the hash andisEqual: methods see NSObject.

Important: Because the dictionary copies each key, keys must conform to the NSCopying protocol. Bear this in mind when choosing what objects to use as keys. Although you can use any object that adopts the NSCopying protocol and implements the hash and isEqual: methods, it is typically bad design to use large objects, such as instances ofNSImage, because doing so may incur performance penalties.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章