The most important collection type is arguably the array. Arrays in Swift are simple to understand, but have a quite rich set of uses with a few new constraints compared to their Objective-C counterparts.
For those unfamiliar with arrays, arrays are an ordered collection of data. Think of an array like a railroad train and each piece of data is a railroad car. We refer to a specific railroad car by how many railroad cars from the front of the train a specific car is. The third car for example my be a dining car. We write this as car[third] where car is the identifier of the array and third is the index. An index is always a positive integer, and arrays in every language I can think of start with zero. That means our index is usually one less than what we expect. If we used numbers for the index, we would write car[2] for the third car.
Swift arrays come in two flavors: dynamic and static. Static arrays keep their size and contents completely: after initialization no changes happen. The code cannot change the elements or the size of the array. Unlike Objective-C ‘s NSArray
, which can change the value of an element, static arrays are completely static. Like any constant, static arrays use memory far more efficiently than dynamic. Dynamic arrays allow us to change the size and contents of the array, similar to NSMutableArray
in Objective-C.
Trying the Examples
For those who want to try the examples, you can open a Playground. Name it SwiftArrays. For those who don’t like playgrounds, you can also create a new single view application. In the ViewController
class, you can add this code to the viewDidLoad
method. Build and run to see the results. In both cases, results will be in the console. Open up the bottom pane of Xcode to see your results. I will sometimes add a print
function to show the results, but not in all cases. If you wish to see a specific result, use print.
Declaring Array in Swift
Compared to Objective-C, Swift arrays are not as picky. Swift accepts any type, not just classes in an array. Declaring static and dynamic arrays is the difference between let
and var
. The let
declaration gives us a static array and the var
a dynamic array. In both cases we set the initial values of the array in the declaration:
let myStaticArray = [ "apple", "pear", "banana", "raspberry" ] var myDynamicArray = [1,2,3,5,7,13,17,23]
Literal arrays are not limited to one physical line. Like myStaticArray
, for readability you can use a separate line for each element of the array. This helps with readability of code. In the examples above, implicit typing can deduce that the static array is a string array and the dynamic is an integer array. We can declare an array of a given type by placing the element’s type in square brackets. An integer dynamic array would look like this:
var myExplicitDynamicArray:[Int] = [1,2,3,5,7,13,17,23]
If we want a empty integer dynamic array, we would declare it like this:
var myEmptyDynamicArray:[Int] = []
or this shorter form:
var myOtherEmptyArray = [Int]()
If you need an array of a certain size with the same data in each element, there is a special initializer for it:
var myVanillaArray = Array(repeating: "Vanilla", count: 5)
This creates an array ["Vanilla","Vanilla","Vanilla","Vanilla","Vanilla"]
Accessing Elements in Swift
To access an element of an array, use the identifier of the array with a subscript enclosed in square brackets. The first element of the array is element 0
. For example
// access first element print(myStaticArray[0]) //fourth element print(myDynamicArray[3]) //add fifth element(7) //to sixth element(13) print(myDynamicArray[4] + myDynamicArray[5])
If you try to access an element outside of the array, you will get a run-time error. If you had this in your code:
print(myStaticArray[10])
You would get the following error when you ran the app:
fatal error: Array index out of range
The index can never be negative. Any negative value such as
print(myStaticArray[-1])
is also out of range and will give an error.
We do know the range of the array due to the count
property, which gives us the number of elements in the array.
print(myStaticArray.count)
Since arrays start at zero, our last element is one less than the count. To access the last element of an array you could write:
print(myStaticArray[myStaticArray.count - 1])
We can get our last element of the array this way
let lastElement = myStaticArray.count - 1 print("\(myStaticArray.count) elements in array") print("last element is \(myStaticArray[lastElement])")
We can also get the last element using the last
property.
print("last element is also \(myStaticArray.last)")
The last
property returns an optional, so you will need to unwrap it.
Iterating Array Data in Swift
If you need to access all elements of an array we can use loops. The best for sequential access is the
for..in
loop
var myArray=[1,2,3,5,7,11,13,17] var total = 0 for element in myArray { print("\(element) ") total += element } print(" = \(total)")
In line 3, the for
loop, starting at the first element of the loop, sequentially gets each value for the array. This works well if you just need the value. Sometimes you need the index of the array, since the code needs multiple indexes. A variation For..in
uses ranges of the index.
total = 0 for index in 1..<myArray.count{ //add an element and the previous element together let sum = myArray[index] + myArray[index-1] total += sum } print(" = \(total)")
Note two things I did here in line 3. I did not write myArray.count-1
. Swift has two range operators. One ...
is a full range. Had I used that, the correct code is 1...myArray.count-1
. Swift has the ..<
operator. This goes one less than the top of the range. Since we use ranges to describe arrays so often, 1..<myArray.count
is cleaner and more understandable code than 1...myArray.count-1
.
Secondly, I started at 1 and not 0. Line four adds the current and the previous array elements together. If I started at 0, I’d get an out of bounds error. Starting at 1 avoids that.
Some cases might have two arrays which share a common index and the same number of elements. Since arrays must have elements of the same type, this situation shows up when you have two arrays of different types you need to associate with each other in a one to one relationship. I might have these two arrays of type String
and Int
respectively:
var iceCreamFlavors=["Vanilla","Chocolate","Strawberry"] var iceCreamLeft=[20,5,50]
Then I would use a for
loop with an index, from 0 to the count
for one of the arrays:
for index in 0..<iceCreamFlavors.count{ print("We have \(iceCreamLeft[index]) units of \(iceCreamFlavors[index]) left") }
this produces the result:
We have 20 units of Vanilla left We have 5 units of Chocolate left We have 50 units of Strawberry left
The for
loops get every case, since they increment index
by one. If you want some increment other than one, you need a while
loop:
// Sum every other element using a while loop total = 0 var index = 0 while index < myArray.count { print("\(index), \(myArray[index])") total += myArray[index] index += 2 } print(" = \(total)")
When I want to work backwards starting at the last element and going to the first element, we also use a while
loop:
//same as the for loop, but counting backwards total = 0 index = myArray.count - 1 while index >= 0 { print("\(index), \(myArray[index])") total += myArray[index] index -= 1 } print(" = \(total)")
Adding and Removing Elements
To add an element to the end of the array, use the .append()
method or the +=
operator. These two statements do the same:
myArray = [1,2,3,5,7,11,13,17] myArray.append(23) myArray += [29]
The array [1,2,3,5,7,11,13,17]
appends two numbers, changing to: [1,2,3,5,7,11,13,17,23,29]
The advantage to the +=
operator is you can append another array if the elements are of the same type in both arrays.
myArray += [31, 37]
results in [1,2,3,5,7,11,13,17,23,29,31,37]
In Swift, operators keep a consistency across type, which might make some traditional programmers a bit squeamish. The +=
in their mind is an arithmetic operator, but it works for many types, including arrays. Swift continues such consistency with merging two arrays with the +
operator
var myStringArray = ["apple","pear","banana","raspberry"] var myOtherStringArray = ["Pepperoni","Sausage"] var jointArray = myStringArray + myOtherStringArray
This code results in jointArray
being ["apple","pear","banana","raspberry","Pepperoni","Sausage"]
To insert an element at a particular position, use the insert:at:
method, remembering that the first index is zero:
myArray.insert(2,at:2)
This results in [1,2,2,3,5,7,11,13,17,23,29,31,37]
To change an element, assign a value to the specific element, like this:
myStringArray = ["apple","banana","raspberry","mango"] myStringArray[1] = "blackberry"
Will change myStringArray
to ["apple","blackberry","raspberry","mango"]
. You can change a range of values if both arrays are the same type.
myStringArray[1...2] = ["beagle bone","arduino"]
Will change ["apple","blackberry","raspberry","mango"]
to ["apple","beagle bone","arduino","raspberry","mango"]
. Range values specify the range to replace. You can replace with fewer items
myStringArray[1...3] = ["blackBerry", "kit kat"]
Changes elements 1,2,3 to only two elements making the array ["apple","beagle bone","arduino","raspberry","mango"]
to ["apple","blackBerry", "kit kat","mango"]
To delete an element, there are two methods, removeAtIndex()
and removeLast()
. To remove the last element in the array
myStringArray.removeLast()
Changes the array ["apple","blackBerry", "kit kat","mango"]
to ["apple", "blackBerry","kit kat"]
If we wanted to delete blackberry which is an index of 1, we would use remove(at:)
:
myStringArray.remove(at:1)
Changes the array to ["Apple","kit kat"]
When passing arrays in parameters we use the same syntax as declaring them:
func listArray(array:[Int]){ for element in array{ print(element) } }
I could then call this function with
listArray(myArray)
Arrays Are for Classes and Types
Arrays can take any class. A common class to place into an array is a custom class for your model. For example , you might have a class to keep track of cookies
//Using arrays in a class class Cookie{ var name = "" var price = 0.00 var rating = 0 init(){} init(name:String,price:Double,rating:Int){ self.name = name self.price = price self.rating = rating } }
In your view controller, you would define an array to hold your all your cookies:
var cookie = [Cookie]() cookie += [Cookie(name: "Chocolate Chip", price: 0.25, rating: 10)] cookie += [Cookie(name: "Oatmeal", price: 0.20, rating: 5)] cookie += [Cookie(name: "Peanut Butter", price: 0.20, rating: 4)] cookie += [Cookie(name: "White Chocolate Macadamia", price: 0.50, rating: 10)] cookie += [Cookie(name: "Butter Ganache", price: 0.35, rating: 9)] cookie += [Cookie(name: "Chcocolate Cream", price: 0.22, rating: 7)]
Several methods in view controllers such as UITableViewController
and UIPickerView
access the array. For example in a picker view we could have this:
//example function -- see UIPickerView references for more detail func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?{ return cookie[row].name }
Optionals and Array
Arrays can be used with optionals. Very often we may set an array to be optional to check for an empty state.
var optionalArray :[String]! = nil
We can also make our elements nil
var optionalElements : [String?] = [nil,"2","3","4",nil,"6"]
Working with Objective-C Arrays in Swift
There are several differences between in Objective-C and Swift. If you need a Objective-C NSArray
because you have an API that uses it, you can always declare your array as:
var myImmutableArray:NSArray! = ["x","y","2"]
Remember that NSArrays
can be nil
, so it ‘s a good idea to make it an optional like I did above. I find Objective-C arrays clunky, and will tend to avoid them if I can. Many of the API’s will bridge Swift and Objective-C without issues so there is little need to do this, but there may be a few places where they don’t. You will need to declare an NSArray
, when an array has elements of multiple classes.
Arrays are a rich, often used data structure. I thought this might help some of them. Hope it did.
The Whole Code
The code below is a playground. Open a playground in Xcode or the playgrounds app and cut and paste this code in. You can also use an IBM sandbox version of this code on the web by clicking the link.
//: Playground - noun: a place where people can play import UIKit //: Swift Arrays -- A demonstration of Arrays //: In Swift 3.0 //:(c)2016 Steven Lipton //: lesson text can be found at [http://wp.me/p2kbUU-7g0] (http://wp.me/p2kbUU-7g0) //Declaring Arrays //Literal static array let myStaticArray = [ "apple", "pear", "banana", "raspberry" ] //literal Dynamic Array var myDynamicArray = [1,2,3,5,7,13,17,23] //Empty Dynamic Arrays //Both of these work var myEmptyDynamicArray:[Int] = [] var myOtherEmptyArray = [Int]() //An array with the same values in all //elements var myVanillaArray = Array(repeating: "Vanilla", count: 5) // access first element print(myStaticArray[0]) //fourth element print(myDynamicArray[3]) //add fifth element(7) //to sixth element(13) print(myDynamicArray[4] + myDynamicArray[5]) //uncomment to produce runtime // out of bounds error //comment out to run code. //myDynamicArray[10] //using count print(myStaticArray.count) //finding the last element with .count let lastElement = myStaticArray.count - 1 print("\(myStaticArray.count) elements in array") print("last element is \(myStaticArray[lastElement])") //last property, note it is optional print("last element is also \(myStaticArray.last)") //for..in loop var myArray=[1,2,3,5,7,11,13,17] var total = 0 for element in myArray { print("\(element) ") total += element } print(" = \(total)") //for loop with range total = 0 for index in 1..<myArray.count{ //add an element and the previous element together let sum = myArray[index] + myArray[index-1] total += sum } print(" = \(total)") // Using a common index for two arrays // often used when you have different types in the two arrays var iceCreamFlavors=["Vanilla","Chocolate","Strawberry"] var iceCreamLeft=[20,5,50] for index in 0..<iceCreamFlavors.count{ print("We have \(iceCreamLeft[index]) units of \(iceCreamFlavors[index]) left") } // Sum every other element using a while loop total = 0 var index = 0 while index < myArray.count { print("\(index), \(myArray[index])") total += myArray[index] index += 2 } print(" = \(total)") //same as the for loop, but counting backwards total = 0 index = myArray.count - 1 while index >= 0 { print("\(index), \(myArray[index])") total += myArray[index] index -= 1 } print(" = \(total)") //add an element either way myArray.append(23) myArray += [29] //add two elements to an array myArray += [31, 37] //concatenation of arrays var myStringArray = ["apple","pear","banana","raspberry","mango"] var myOtherStringArray = ["Pepperoni","Sausage"] var jointArray = myStringArray + myOtherStringArray //insertion myArray.insert(2,at:2) //modifying elements myStringArray[1] = "blackberry" print(myStringArray) //modifying more than one element 1:1 myStringArray[1...2] = ["beagle bone","arduino"] print(myStringArray) //modfying more than one element, // but changing less than the number of elements myStringArray[1...3] = ["blackBerry", "kit kat"] print(myStringArray) //delete last element of the array myStringArray.removeLast() print(myStringArray) //delete selected element in the array myStringArray.remove(at:1) print(myStringArray) //making a function with an array as a parameter func listArray(_ array:[Int]){ for element in array{ print(element) } } listArray(myArray) //Using arrays in a class class Cookie{ var name = "" var price = 0.00 var rating = 0 init(){} init(name:String,price:Double,rating:Int){ self.name = name self.price = price self.rating = rating } } // create array from a class var cookie = [Cookie]() cookie += [Cookie(name: "Chocolate Chip", price: 0.25, rating: 10)] cookie += [Cookie(name: "Oatmeal", price: 0.20, rating: 5)] cookie += [Cookie(name: "Peanut Butter", price: 0.20, rating: 4)] cookie += [Cookie(name: "White Chocolate Macadamia", price: 0.50, rating: 10)] cookie += [Cookie(name: "Butter Ganache", price: 0.35, rating: 9)] cookie += [Cookie(name: "Chcocolate Cream", price: 0.22, rating: 7)] //example function -- see UIPickerView references for more detail /* Non functional example func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?{ return cookie[row].name } */ //Arrays and optionals //optional array var optionalArray :[String]! = nil //optional Array elements var optionalElements : [String?] = [nil,"2","3","4",nil,"6"] //arrays for use with Objective-C code var myImmutableArray:NSArray! = ["x","y","2"] print(myImmutableArray)
Leave a Reply