Tag Archives: NSDictionary

How to access values in a Swift Dictionary

Swift has its own dictionaries, much like Objective-C has the NSDictionary class. Although the two are bridged, they are not the same: trusty old NSDictionary methods do not work with Swift Dictionaries.

Here’s a quick summary of how Swift Dictionaries work.

Creating and iterating over Swift Dictionaries

Let’s create a Swift Dictionary and then list all its values using Fast Enumeration:

// make a Swift Dictionary (Option 1)
var dict: Dictionary = ["key1": "Value 1", "key2": "Value 2", "key3": "Value 3"]

// or, specifying the key/value types (Option 2)
var dict: [String: String] = ["key1": "Value 1", "key2": "Value 2", "key3": "Value 3"]

// or, specifying nothing at all and let everything be inferred (Option 3)
var dict = ["key1": "Value 1", "key2": "Value 2", "key3": "Value 3"]

// list all values
for (key, value) in dict {
    print(key, value)
}

// output: 
key1 Value 1
key3 Value 3
key2 Value 2

The easiest way to create a dictionary is Option 3, letting the compiler infer everything. The other two options are valid too.

What’s special in comparison to NSDictionaries is that in Swift, we can pass both the key and the value to the for loop, rather than just the key.

Accessing a single key’s value

What the elaborate Apple documentation doesn’t explicitly mention for stupid people like me is how to access a single value in the Swift Dictionary. It’s surprisingly simple:

// list a single key's value
print("Value for key1 is", dict["key1"])

// output
Value for key1 is Value 1

Changing a value in our dictionary

We can use the same syntax to update a value in our Swift Dictionary too. Notice that the dictionary must be declared as a variable rather than a constant. The compiler is nice enough to offer this service free of charge:

// change the value of key1 to something else
dict["key1"] = "New Value"
print("Value for key1 is now", dict["key1"])

// output
Value for key1 is now New Value

Adding key/value pairs to our dictionary

To add another key/value pair, we’ll pretend it already exists and simply set its value:

// add a key/value pair 
dict["key4"] = "Brand New Item"

Counting all entries in the dictionary

To see how many key/value pairs we have in our dictionary, we can call the count method:

// how large is the array?
print("The dictionary has", dict.count, "entries.")

// output
The dictionary has 3 entries.

Clearing out a Swift Dictionary

To empty the whole dictionary from all keys and values without destroying the whole thing, we can use this:

// empty my dictionary
dict = [:]
print("The dictionary now has", dict.count, "entries.")

// output
The dictionary has 0 entries.

This is different to setting the dictionary to nil because it leaves the key/value types in place (here: String and String).

Further Reading





What is the difference between NSSet, NSArray and NSDictionary

Bottle CollectionAll three are collection objects that can hold any number of other Objective C objects. I’m sure you’re familiar with the NSArray class, but the other two may sound a bit exotic. Let me explain them all here.

To do this I’m using NSString objects, but all three can pretty much hold any NSObject you encounter – you can even mix object types. For example, you can mix NSString and NSDate objects in the same collection.

NSArray

An NSArray can hold objects in a sorted order. So object1 is always object1, and object2 is always object2. You can retrieve the first and last object from the array.

Here’s how to create one:

// create an array with some values
NSArray *array = @[@"One", @"Two", @"Three", @"Four", @"Five", @"Six"];

// loop through the array
for (NSString *thisString in array) {
    NSLog(@"%@", thisString);
}

This will print all elements in order:

2014-04-07 19:58:14.541 SetTest[542:303] One
2014-04-07 19:58:14.543 SetTest[542:303] Two
2014-04-07 19:58:14.543 SetTest[542:303] Three
2014-04-07 19:58:14.544 SetTest[542:303] Four
2014-04-07 19:58:14.544 SetTest[542:303] Five
2014-04-07 19:58:14.544 SetTest[542:303] Six

NSSet

An NSSet is much like an NSArray, the only difference is that the objects it holds are not ordered. So when you retrieve them they may come back in any random order, based on how easy it is for the system to retrieve them.

You would typically use a set when access speed is of the essence and order doesn’t matter, or is determined by other means (through a predicate or sort descriptor). Core Data for example uses sets when managed objects are accessed via a to-many relationship.

You can turn NSSets into NSArrays and back, and you can fast-enumerate an NSSet too:

// create an array with some values
NSArray *array = @[@"One", @"Two", @"Three", @"Four", @"Five", @"Six"];

// turn them into a set
NSSet *mySet = [[NSSet alloc]initWithArray:array];

// loop through the set
for (NSString *thisString in mySet) {
    NSLog(@"%@", thisString);
}

// turn the set back into an array
NSArray *newArray = [mySet allObjects];

This may print something like this:

2014-04-07 19:42:59.123 SetTest[477:303] Five
2014-04-07 19:42:59.123 SetTest[477:303] Six
2014-04-07 19:42:59.124 SetTest[477:303] One
2014-04-07 19:42:59.124 SetTest[477:303] Three
2014-04-07 19:42:59.124 SetTest[477:303] Four
2014-04-07 19:42:59.125 SetTest[477:303] Two

NSDictionary

The NSDictionary class is a bit of a magical one: it stores objects as key value pairs. Objects are not ordered, but can be retrieved simply by addressing them with an arbitrary string value.

Here we create one with three keys and values, then loop through it:

// create an array with some values
NSDictionary *dictionary = @{@"name": @"Chuck Norris",
                             @"title": @"Movie Star",
                             @"tvShow": @"Walker, Texas Ranger"
                             };

// loop through the set
for (NSString *key in dictionary) {
    
    NSString *value = [dictionary valueForKey:key];
    NSLog(@"%@: %@", key, value);
}

This will print:

2014-04-07 20:12:52.100 SetTest[580:303] name: Chuck Norris
2014-04-07 20:12:52.102 SetTest[580:303] title: Movie Star
2014-04-07 20:12:52.103 SetTest[580:303] tvShow: Walker, Texas Ranger





How to test the size of an NSDictionary (in bytes)

The NSDictionary class doesn’t have a length property that can tell us how much memory is being used for storing the whole lot. Usually we don’t really care how big our variables grow – but if you’re storing that dictionary somewhere with potentially limited space (such as iCloud Key/Value storage), it may well be of interest.

You can however turn the dictionary into data and test its size like this:

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
for (int i = 0; i <= 1000; i++) {
        
    NSString *key = [[NSString alloc]initWithFormat:@"Key%i", i];
    [dictionary setObject:@47 forKey:key];
}
NSData * data = [NSPropertyListSerialization dataFromPropertyList:dictionary format:NSPropertyListBinaryFormat_v1_0 errorDescription:NULL];

NSLog(@"Size in bytes: %lu - Entries: %lu", (unsigned long)[data length], (unsigned long)dictionary.count);

Here we setup a loop that generates a dictionary and adds 1001 entries with an NSNumber literal of 47. This will give us the following information:

Size in bytes: 12954 – Entries: 1001

Note that the above only works if your dictionary has “serialisable” data such as NSNumber, NSDate, NSArray, NSDictionary, NSString or NSData (anything that can be written to a .plist file basically) – but it will not work with custom objects.





How to loop through every element in an NSArray

We can use something called Fast Enumeration for this, using a modified for loop:

// build an array
NSArray *myArray = [[NSArray alloc]initWithObjects:@"One", @"Two", @"Three", @"Four", nil];

// loop through every element (dynamic typing)
for (id tempObject in myArray) {
    NSLog(@"Single element: %@", tempObject);
}

You don’t have to use dynamic typing if you know the types of objects you’re using. In our example this would work just as well:

// build an array
NSArray *myArray = [[NSArray alloc]initWithObjects:@"One", @"Two", @"Three", @"Four", nil];

// loop through every element (static typing)
for (NSString *tempObject in myArray) {
    NSLog(@"Single element: %@", tempObject);
}

Fast Enumeration also works with NSDictionaries of course:

// build a dictionary
NSDictionary *myDictionary = [[NSDictionary alloc]initWithObjectsAndKeys:@"One", @"1", @"Two",@"2", @"Three", @"3",nil];

// loop through it (dynamic typing)
for (id tempObject in myDictionary) {
    NSLog(@"Object: %@, Key: %@", [myDictionary objectForKey:tempObject], tempObject);
}