Swift 3 Basics

Posted on September 28, 2016


Optionals

Forced Unwrapping

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}

Optional Binding

if let actualNumber = Int(possibleNumber) {
    print("\"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
    print("\"\(possibleNumber)\" could not be converted to an integer")
}

Nil-Coalescing Operator

a ?? b unwraps an optional a if it contains a value, or returns a default value b if a is nil. Same as a != nil ? a! : b

Collections

Array: Array<Element> or var someInts = [Int]() Set:

Double

Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. In situations where either type would be appropriate, Double is preferred. Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers.

Conversions between integer and floating-point numeric types must be made explicit:

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine

In-Out Parameters

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. You write an in-out parameter by placing the inout keyword right before a parameter’s type. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an in-out parameter, to indicate that it can be modified by the function.

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var testA = 3, testB = 4
swap(&testA, &testB)

In-out parameters are an alternative way for a function to have an effect outside of the scope of its function body.

The mutating keyword

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends.

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"

The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

Mutating methods for enumerations can set the implicit self parameter to be a different case from the same enumeration.

Type Casting

Use the type check operator is to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.

You can use the is and as operators in a switch statement’s cases to discover the specific type of a constant or variable that is known only to be of type Any or AnyObject.

Use the conditional form of the type cast operator as? when you are not sure if the downcast will succeed.

Use the forced form of the type cast operator as! only when you are sure that the downcast will always succeed.

for item in library {
    if let movie = item as? Movie {
        print("Movie: \(movie.name), dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: \(song.name), by \(song.artist)")
    }
}

Stay in touch!