[Updated to Swift 2.0 9/15/15 SJL]
Note: this is a Swift 2.0 version. You can find the Swift 3.0 Version of this tutorial here
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 for example . 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 for example.
Swift arrays come in two flavors: dynamic and static. Static arrays maintain 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.
Unlike Objective-C, the elements of an array must be of the same type. 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(count: 5, repeatedValue: "Vanilla")
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 myStaticArray[0] //fourth element myDynamicArray[3] //add fifth element(7) //to sixth element(13) 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
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])
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 an full range. Had I used that, the correct code is 1...myArray.count-1
. Xcode beta 3 and later 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
. For those who get an error using ..<
, you need to update Xcode to the current version.
Secondly, I started at 1 and not 0. Line four adds the current and the last array elements together. If I started at 0, I’d get an out of bounds error. Starting at 1 avoids that.
The For..in
loop is the correct choice for sequential access of the array. This is most cases. There are times I want to start at the last element and go to the first element, or possibly look at every other element. For that we need a more traditional C- type loop. In a more C-type for loop we can do the following:
// same sum as the last code using a traditional for total = 0 for var index:Int = 1 ; index < myArray.count ;index++ { let sum = myArray[index] + myArray[index-1] total += myArray[index] + myArray[index-1] } print(" = \(total)")
Line 3 initializes a variable index
to 1, and then continues to loop, increasing the index by 1 as long as the index is less than myArray.count
. We can count from the last element to the first this way:
//same as the last code, but counting backwards total = 0 for var index:Int = myArray.count - 1 ; index >= 1 ;index-- { let sum = myArray[index] + myArray[index-1] total += myArray[index] + myArray[index-1] } print(" = \(total)")
Here I start with a large value and loop, decrementing index
until it is less than 0.
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. You should not use it for arrays, only for incrementing numbers, like we did in the for
loop. 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:index) method
, remembering that the first index is zero:
myArray.insert(2,atIndex: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"] myStringArray[1] = "blackberry"
Will change myStringArray
to ["apple","blackberry","banana","raspberry"]
. You can change a range of values if both arrays are the same type.
myStringArray[1...2] = ["beagle bone","arduino"]
Will change ["apple","blackberry","banana","raspberry"]
to ["apple","beagle bone","arduino","raspberry"]
. 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"]
to ["apple","blackBerry", "kit kat"]
To delete an element, there are two methods, removeAtIndex()
and removeLast()
. To remove the last element in the array
myStringArray.removeLast()
Changes the array to ["Apple", "BlackBerry","Raspberry","BeagleBone","Arduino"]
If we wanted to delete Blackberry or any other element but the last, we would use removeAtIndex()
:
myStringArray.removeAtIndex(1)
Changes the array to ["Apple","Raspberry","BeagleBone","Arduino","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, particualrly one that has a UITableView or UIPickerView, 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)]
In some function forRow
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 }
See the post The Swift Swift Tutorial: How to Use UITableView in Swift I mentioned above for a good example of this in tables. For pickers see the post for more information about using UIPickerView.
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"]
Going Back to the Old Arrays
As I’ve noted above, there are several differences between in Objective-C and Swift. If you like a Objective-C NSArray more than Swift’s Array type or have some legacy code to translate, you can always declare your array as one:
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 still no 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 had a few questions lately in comments about data structures in Swift, So I thought this might help some of them. Hope it did.
The Whole Code
//: Playground - noun: a place where people can play import UIKit // SwiftArrays -- A demonstration of Arrays // In Swift 2.0 //(c)2015 Steven Lipton //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(count: 5, repeatedValue: "Vanilla") // access first element myStaticArray[0] //fourth element myDynamicArray[3] //add fifth element(7) //to sixth element(13) myDynamicArray[4] + myDynamicArray[5] //uncomment to produce runtime // out of bounds error //comment out to run code. //myDynamicArray[10] //finding the last element with .count myStaticArray.count myStaticArray[myStaticArray.count - 1] //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)") // same sum as the last code using a traditional for total = 0 for var index:Int = 1 ; index < myArray.count ;index++ { let sum = myArray[index] + myArray[index-1] total += myArray[index] + myArray[index-1] } print(" = \(total)") //same as the last code, but counting backwards total = 0 for var index:Int = myArray.count - 1 ; index >= 1 ;index-- { let sum = myArray[index] + myArray[index-1] total += myArray[index] + myArray[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"] var myOtherStringArray = ["Pepperoni","Sausage"] var jointArray = myStringArray + myOtherStringArray //insertion myArray.insert(2,atIndex:2) //modifying elements myStringArray[1] = "blackberry" myStringArray //modifying more than one element 1:1 myStringArray[1...2] = ["beagle bone","arduino"] myStringArray //modfying more than one element, // but changing less than the number of elements myStringArray[1...3] = ["blackBerry", "kit kat"] myStringArray //delete last element of the array myStringArray.removeLast() myStringArray //delete selected element in the array myStringArray.removeAtIndex(1) 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 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"]
Leave a Reply