Changes

Working with Array and Dictionary Collections in Swift 2

15,266 bytes added, 21:55, 14 December 2015
New page: <table border="0" cellspacing="0" width="100%"> <tr> <td width="20%">Previous<td align="center">[[iOS 9 App Development Essentials|T...
<table border="0" cellspacing="0" width="100%">
<tr>
<td width="20%">[[An Introduction to Swift Subclassing and Extensions|Previous]]<td align="center">[[iOS 9 App Development Essentials|Table of Contents]]<td width="20%" align="right">[[Understanding Error Handling in Swift 2|Next]]</td>
<tr>
<td width="20%">An Introduction to Swift Subclassing and Extensions<td align="center"><td width="20%" align="right">Understanding Error Handling in Swift 2</td>
</table>
<hr>


<google>BUY_IOS9</google>


Arrays and dictionaries in Swift are objects that contain collections of other objects. In this chapter, we will cover some of the basics of working with arrays and dictionaries in Swift.

== Mutable and Immutable Collections ==

Collections in Swift come in mutable and immutable forms. The contents of immutable collection instances cannot be changed after the object has been initialized. To make a collection immutable, assign it to a constant when it is created. Collections are mutable, on the other hand, if assigned to a variable.

== Swift Array Initialization ==

An array is a data type designed specifically to hold multiple values in a single ordered collection. An array, for example, could be created to store a list of String values. Strictly speaking, a single Swift based array is only able to store values that are of the same type. An array declared as containing String values, therefore, could not also contain an Int value. As will be demonstrated later in this chapter, however, it is also possible to create mixed type arrays. The type of an array can be specified specifically using type annotation, or left to the compiler to identify using type inference.

An array may be initialized with a collection of values (referred to as an array literal) at creation time using the following syntax:

<pre>
var variableName: [type] = [value 1, value2, value3, .... ]
</pre?

The following code creates a new array assigned to a variable (thereby making it mutable) that is initialized with three string values:

<pre>
var treeArray = ["Pine", "Oak", "Yew"]
</pre>

Alternatively, the same array could have been created immutably by assigning it to a constant:

<pre>
let treeArray = ["Pine", "Oak", "Yew"]
</pre>

In the above instance, the Swift compiler will use type inference to decide that the array contains values of String type and prevent values of other types being inserted into the array elsewhere within the application code.

Alternatively, the same array could have been declared using type annotation:

<pre>
var treeArray: [String] = ["Pine", "Oak", "Yew"]
</pre>

Arrays do not have to have values assigned at creation time. The following syntax can be used to create an empty array:

<pre>
var variableName = [type]()
</pre>

Consider, for example, the following code which creates an empty array designated to store floating point values and assigns it to a variable named priceArray:

<pre>
var priceArray = [Float]()
</pre>

Another useful initialization technique allows an array to be initialized to a certain size with each array element pre-set with a specified default value:

<pre>
var nameArray = [String](count: 10, repeatedValue: "My String")
</pre>

When compiled and executed, the above code will create a new 10 element array with each element initialized with a string that reads “My String”.

Finally, a new array may be created by adding together two existing arrays (assuming both arrays contain values of the same type). For example:

<pre>
var firstArray = ["Red", "Green", "Blue"]
var secondArray = ["Indigo", "Violet"]

var thirdArray = firstArray + secondArray
</pre>

== Working with Arrays in Swift ==

Once an array exists, a wide range of methods and properties are provided for working with and manipulating the array content from within Swift code, a subset of which is as follows:

=== Array Item Count ===

A count of the items in an array can be obtained by accessing the array’s count property:

<pre>
var treeArray = ["Pine", "Oak", "Yew"]
var itemCount = treeArray.count

print(itemCount)
</pre>

Whether or not an array is empty can be identified using the array’s Boolean isEmpty property as follows:
var treeArray = ["Pine", "Oak", "Yew"]

<pre>
if treeArray.isEmpty {
// Array is empty
}
</pre>

=== Accessing Array Items ===

A specific item in an array may be accessed or modified by referencing the item’s position in the array index (where the first item in the array has index position 0) using a technique referred to as index subscripting. In the following code fragment, the string value contained at index position 2 in the array (in this case the string value “Yew”) is output by the print call:

<pre>
var treeArray = ["Pine", "Oak", "Yew"]

print(treeArray[2])
</pre>

This approach can also be used to replace the value at an index location:

<pre>
treeArray[1] = "Redwood"
</pre>

The above code replaces the current value at index position 1 with a new String value that reads “Redwood”.

== Appending Items to an Array ==

Items may be added to an array using either the append method or + and += operators. The following, for example, are all valid techniques for appending items to an array:

<pre>
treeArray.append("Redwood")
treeArray += ["Redwood"]
treeArray += ["Redwood", "Maple", "Birch"]
</pre>

=== Inserting and Deleting Array Items ===

New items may be inserted into an array by specifying the index location of the new item in a call to the array’s insert(atIndex:) method. An insertion preserves all existing elements in the array, essentially moving them to the right to accommodate the newly inserted item:

<pre>
treeArray.insert("Maple", atIndex: 0)
</pre>

Similarly, an item at a specific array index position may be removed using the removeAtIndex method call:

<pre>
treeArray.removeAtIndex(2)
</pre>

To remove the last item in an array, simply make a call to the array’s removeLast method as follows:

<pre>
treeArray.removeLast()
</pre>

=== Array Iteration ===

The easiest way to iterate through the items in an array is to make use of the for-in looping syntax. The following code, for example, iterates through all of the items in a String array and outputs each item to the console panel:
<google>BUY_IOS9</google>
<pre>
var treeArray = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"]

for tree in treeArray {
print(tree)
}
</pre>

Upon execution, the following output would appear in the console:

<pre>
Pine
Oak
Yew
Maple
Birch
Myrtle
</pre>

== Creating Mixed Type Arrays ==

A mixed type array is an array that can contain elements of different class types. Clearly an array that is either declared or inferred as being of type String cannot subsequently be used to contain non-String class object instances. Interesting possibilities arise, however, when taking into consideration that Swift includes the AnyObject type. AnyObject is a special type in Swift that can be used to reference an object of a non-specific class type. It follows, therefore, that an array declared as containing AnyObjects can be used to store elements of mixed types. The following code, for example, declares and initializes an array containing a mixture of String, Int and Double elements:

<pre>
let mixedArray: [AnyObject] = [“A String”, 432, 34.989]
</pre>

In actual fact, an array declared without any type but assigned elements of mixed types will be inferred by Swift as being of AnyObject type:

<pre>
let mixedArray = [“A String”, 432, 34.989]
</pre>

The use of AnyObject should be used with care since the use of AnyObject masks from Swift the true type of the elements in such an array thereby leaving code prone to potential programmer error. It will often be necessary, for example, to manually cast the elements in an AnyObject array to the correct type before working with them in code. Performing the incorrect cast for a specific element in the array will most likely cause the code to compile without error but crash at runtime. Consider, for the sake of an example, the following mixed type array:

<pre>
let mixedArray: [AnyObject] = [1, 2, 45, "Hello"]
</pre>

Assume that, having initialized the array, we now need to iterate through the integer elements in the array and multiply them by 10. The code to achieve this might read as follows:

<pre>
for object in mixedArray {
print(object * 10)
}
</pre>

When entered into Xcode, however, the above code will trigger a syntax error indicating that it is not possible to multiply operands of type AnyObject and Int. In order to remove this error it will be necessary to downcast the array element to be of type Int:

<pre>
for object in mixedArray {
print(object as! Int * 10)
}
</pre>

The above code will compile without error and work as expected until the final String element in the array is reached at which point the code will crash with the following error:

<pre>
Could not cast value of type ‘Swift._NSContinuousString’ to ‘NSNumber’
</pre>

The code will, therefore, need to be modified to be aware of the specific type of each element in the array. Clearly, there are both benefits and risks to using AnyObject arrays in Swift.

== Swift Dictionary Collections ==

String dictionaries allow data to be stored and managed in the form of key-value pairs. Dictionaries fulfill a similar purpose to arrays, except each item stored in the dictionary has associated with it a unique key (to be precise, the key is unique to the particular dictionary object) which can be used to reference and access the corresponding value. Currently only String, Int, Double and Bool data types are suitable for use as keys within a Swift dictionary.

== Swift Dictionary Initialization ==

A dictionary is a data type designed specifically to hold multiple values in a single unordered collection. Each item in a dictionary consists of a key and an associated value. The data types of the key and value elements type may be specified specifically using type annotation, or left to the compiler to identify using type inference.

A new dictionary may be initialized with a collection of values (referred to as a dictionary literal) at creation time using the following syntax:

<pre>
var variableName: [key type: value type] = [key 1: value 1, key 2: value2 …. ]
</pre>

The following code creates a new array assigned to a variable (thereby making it mutable) that is initialized with four key-value pairs in the form of ISBN numbers acting as keys for corresponding book titles:

<pre>
var bookDict = ["100-432112" : "Wind in the Willows",
"200-532874" : "Tale of Two Cities",
"202-546549" : "Sense and Sensibility",
"104-109834" : "Shutter Island"]
</pre>

In the above instance, the Swift compiler will use type inference to decide that both the key and value elements of the dictionary are of String type and prevent values or keys of other types being inserted into the dictionary.

Alternatively, the same array could have been declared using type annotation:

<pre>
var bookDict: [String: String] =
["100-432112" : "Wind in the Willows",
"200-532874" : "Tale of Two Cities",
"202-546549" : "Sense and Sensibility",
"104-109834" : "Shutter Island"]
</pre>

As with arrays, it is also possible to create an empty dictionary, the syntax for which reads as follows:

<pre>
var variableName = [key type: value type]()
</pre>

The following code creates an empty dictionary designated to store integer keys and string values:

<pre>
var myDictionary = [Int: String]()
</pre>

=== Dictionary Item Count ===

A count of the items in a dictionary can be obtained by accessing the dictionary’s count property:

<pre>
var bookDict: [String: String] =
["100-432112" : "Wind in the Willows",
"200-532874" : "Tale of Two Cities",
"202-546549" : "Sense and Sensibility",
"104-109834" : "Shutter Island"]

print(bookDict.count)
</pre>

=== Accessing and Updating Dictionary Items ===

A specific value may be accessed or modified using key subscript syntax to reference the corresponding key. The following code references a key known to be in the bookDict dictionary and outputs the associated value (in this case the book entitled “A Tale of Two Cities”):

<pre>
print(bookDict["200-532874"])
</pre>

A similar approach can be used when updating the value associated with a specified key, for example, to change the title of the same book from “At Tale of Two Cities” to “Sense and Sensibility”):

<pre>
bookDict["200-532874"] = "Sense and Sensibility"
</pre>

The same result is also possible by making a call to the updateValue(forKey:) method, passing through the key corresponding to the value to be changed:

<pre>
bookDict.updateValue("The Ruins", forKey: "200-532874")
</pre>

=== Adding and Removing Dictionary Entries ===

Items may be added to a dictionary using the following key subscripting syntax:

<pre>
dictionaryVariable[key] = value
</pre>

For example, to add a new key-value pair entry to the books dictionary:

<pre>
bookDict["300-898871"] = "The Overlook"
</pre>

Removal of a key-value pair from a dictionary may be achieved either by assigning a nil value to the entry, or via a call to the removeValueForKey method of the dictionary instance. Both code lines below achieve the same result of removing the specified entry from the books dictionary:

<pre>
bookDict["300-898871"] = nil
bookDict.removeValueForKey("300-898871")
</pre>

=== Dictionary Iteration ===

As with arrays, it is possible to iterate through the dictionary entries by making use of the for-in looping syntax. The following code, for example, iterates through all of the entries in the books dictionary, outputting both the key and value for each entry panel:

<pre>
for (bookid, title) in bookDict {
print("Book ID: \(bookid) Title: \(title)")
}
</pre>

Upon execution, the following output would appear in the console:

<pre>
Book ID: 100-432112 Title: Wind in the Willows
Book ID: 200-532874 Title: The Ruins
Book ID: 104-109834 Title: Shutter Island
Book ID: 202-546549 Title: Sense and Sensibility
</pre>

== Summary ==

Collections in Swift take the form of either dictionaries or arrays. Both provide a way to collect together multiple items within a single object. Arrays provide a way to store an ordered collection of items where those items are accessed by an index value corresponding to the item position in the array. Dictionaries provide a platform for storing key-value pairs, where the key is used to gain access to the stored value. Iteration through the elements of Swift collections can be achieved using the for-in loop construct.


<google>BUY_IOS9</google>


<hr>
<table border="0" cellspacing="0" width="100%">
<tr>
<td width="20%">[[An Introduction to Swift Subclassing and Extensions|Previous]]<td align="center">[[iOS 9 App Development Essentials|Table of Contents]]<td width="20%" align="right">[[Understanding Error Handling in Swift 2|Next]]</td>
<tr>
<td width="20%">An Introduction to Swift Subclassing and Extensions<td align="center"><td width="20%" align="right">Understanding Error Handling in Swift 2</td>
</table>