DEV Community

Cover image for Intro to Swift Collections
Timothy Fosteman
Timothy Fosteman

Posted on • Updated on

Intro to Swift Collections

My notes of Swift 5 language study

Built-In Collections

Collections of different kinds are supported by the standard library. Evermore does Swift put emphasis on sequences and collections resulting in very extensible model.

Arrays and Mutability

Most common collections in Swift - an ordered container of elements of the same type, providing random element access.

let FibonacciNumbers = [0, 1, 1, 2, 3, 5]

Modification of this array using append(_:) will result in compile error. How come?!

Because let defines constants, while var variables.

Stick to constant by default, it's safer.

var mutableFibs = [0, 1, 1, 2, 3, 5]
mutableFibs.append(8)
mutableFibs.append(contentsOf: [13, 21])
// [0, 1, 1, 2, 3, 5, 8, 13, 21]

Evidently, let variable containing reference to a class instance guarantees that the reference will never change, but he object the reference points to can chang, indeed.

Value semantics

An existing array assigned to a different variable copies it over.

var x = [1, 2, 3]
var y = x
y.append(4)

x is never modified, while a copy of it is made. Same thing happens with passing an array to a function - a local copy is made.

If to peep in NSArray of Foundation, there are no mutating methods. NSMutableArray is needed. But non-mutating NSArray reference can be mutated "underneath"

let a = NSMutableArray(array: [1,2,3])
// I want a to be immutable

let b: NSArray = a

a.insert(4, at:3)

//fail :)

The correct way to write this therefore is to create a copy upon assignment

let c = NSMutableArray(array: [1,2,3])
//I want d to be immutable

let d = c.copy() as! NSArray

c.insert(4, at: 3)

Array Indexing

Swift arrays provide all the usual operations like isEmpty, subscripting [], and count.
Fatal errors occur whenever out-of-bounds elements are requested.

Iteration over an array

for x in array

Iterate over all but the first element

for x in array.dropFirst()

Iterate over all but the last five elements

for x in array.dropLast(5)

Number all the elements

for (num, element) in array.enumerated()

Find location of a specific element

if let index = array.firstIndex {
    return matchingLogic($0)
}

Transform all the elements

array.map {
    return transformLogic($0)
}

Fetch only the creterion matching elements

array.filter {
    match($0)
}

Note: subscripting operation that responds to an invalid index with a fatal error is arguably an "unsafe" operation. Swift discourages use of indecis. Mind, though, that subscripting in regard to memory safety always performs bound checks to prevent null pointer exception

Other operations like first and last return an optional value, which is nil if the array is empty.
removeLast method will halt if called on empty array, popLast is safe.If array is used as a a stack checking for emptiness is encouraged so as not to fiddle with optional.

map

var squared: [Int] = []
for fib in FibonacciNumbers {
    squared.append(fib * fib)
}
squared // [0, 1, 1, 4, 9, 25]

let squares = FibonacciNumbers.map {fib in fib * fib}
squares // [0, 1, 1, 4, 9, 25]

As a side note, map method isn't hard to write, it's a generic for loop
Element is the generic placeholder fpr whatever type the array contains, amd T is a new placeholder that represent the result of the elelement transformation. MyMap function is oblivious to the types.

Ideally thought, signature must be func MyMap<T>(_ transform:(Element) throws -> T) rethrows -> [T], meaning that MyMap will forward any error the transformation function might through to the caller.

Discussion (0)