I’m starting to learn SwiftUI by following a course on Stanford’s Website called CS193p – Developing Apps for iOS. There are specific assigned readings and that is what I took notes on below. Part 2 is here, and the rest of the course notes can be found here.
The Basics
- You can declare multiple constants or multiple variables on a single line, separated by commas:
var x = 0.0, y = 0.0, z = 0.0
- You can provide a type annotation when you declare a constant or variable, to be clear about the kind of values the constant or variable can store: var welcomeMessage: String. Note that it’s rare to actually do this in practice though.
- You can define multiple related variables of the same type on a single line, separated by commas, with a single type annotation after the final variable name: var red, green, blue: Double
- String interpolation is as follows:
print("The value of friendlyWelcome is \(friendlyWelcome)")
Semicolons are only required if you want to write multiple separate statements on a single line such as let cat = “????”; print(cat)
Double
has a precision of at least 15 decimal digits, whereas the precision ofFloat
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 thanFloat
) when you input an initial value that includes a decimal point such as 3.14. - If you combine integer and floating-point literals in an expression, a type of
Double
will be inferred from the context:
let anotherPi = 3 + 0.14159
Tuples
Tuples enable you to create and pass around groupings of values. You can use a tuple to return multiple values from a function as a single compound value. So basically Tuples group multiple values into a single compound value. You can retrieve a tuple’s value with the below code ????
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// Prints "The status code is 404"
If you only need some of the tuple’s values, ignore parts of the tuple with an underscore _
An example is below ????
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"
Alternatively, access the individual element values in a tuple using index numbers starting at zero:
print("The status code is \(http404Error.0)")
// Prints "The status code is 404"
print("The status message is \(http404Error.1)")
// Prints "The status message is Not Found"
You can name the individual elements in a tuple when the tuple is defined, kind of like values in an array: let http200Status = (statusCode: 200, description: “OK”). If you name the elements in a tuple, you can use the element names to access the values of those elements:
print("The status code is \(http200Status.statusCode)")
// Prints "The status code is 200"
print("The status message is \(http200Status.description)")
// Prints "The status message is OK"
Assertions & Preconditions
Assertions and preconditions are checks that happen at runtime. Assertions help you find mistakes and incorrect assumptions during development, and preconditions help you detect issues in production. The difference between assertions and preconditions is in when they’re checked: Assertions are checked only in debug builds, but preconditions are checked in both debug and production builds. In production builds, the condition inside an assertion isn’t evaluated. This means you can use as many assertions as you want during your development process, without impacting performance in production.
An example of an Assertion is below. Note that an assertion message is not required, but it is helpful.
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 0.
If the code already checks the condition (like in an if statement), you can use the assertionFailure() function to indicate that an assertion has failed. For example:
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
print("You can ride the ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
Use a Precondition whenever a condition has the potential to be false, but must definitely be true for your code to continue execution. An example is below ????
precondition(index > 0, "Index must be greater than zero.")
You can use the fatalError() function during prototyping and early development to create stubs for functionality that hasn’t been implemented yet, by writing fatalError(“Unimplemented”) as the stub implementation.
Basic Operators
The values that operators affect are operands. In the expression 1 + 2
, the +
symbol is a binary operator and its two operands are the values 1
and 2
.
The remainder operator (%
) is also known as a modulo operator in other languages. However, its behavior in Swift for negative numbers means that, strictly speaking, it’s a remainder rather than a modulo operation.
9 % 4 // equals 1
You can compare two tuples if they have the same type and the same number of values. Tuples are compared from left to right, one value at a time, until the comparison finds two values that aren’t equal. Those two values are compared, and the result of that comparison determines the overall result of the tuple comparison. When the tuples’ first elements are the same their second elements are compared.
A ternary conditional operator is a special operator with three parts, which takes the form question ? answer1 : answer2
. If question
is true, it evaluates answer1
and returns its value; otherwise, it evaluates answer2
and returns its value.
Strings & Characters
If you need a string that spans several lines, use a multiline string literal—a sequence of characters surrounded by three double quotation marks. If you want to use line breaks to make your source code easier to read, but you don’t want the line breaks to be part of the string’s value, write a backslash (\
) at the end of those lines
let softWrappedQuotation = """
The White Rabbit put on his spectacles. "Where shall I begin, \
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on \
till you come to the end; then stop."
"""
if emptyString.isEmpty {
print("Nothing to see here")
}
for character in "Dog!????" {
print(character)
}
You can create a standalone character with let exclamationMark: Character = “!” And you can also turn an array of characters into a string by using the below code:
let catString = String(catCharacters)
To retrieve a count of the Character
values in a string, use the count
property of the string. Example is stringName.count
You can use the use the insert(_:at:)
and remove(at:)
methods to insert or remove a certain character within a string.
Collection Types
Swift provides three primary collection types, known as arrays, sets, and dictionaries, for storing collections of values. Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.
Arrays
You can use the .count method to find out how many items are in an array.
Use the Boolean isEmpty
property as a shortcut for checking whether the count
property is equal to 0
:
You can add a new item to the end of an array by calling the array’s append(_:)
method. Alternatively, append an array of one or more compatible items with the addition assignment operator (+=
): The two examples are shown below:
shoppingList.append("Flour")
shoppingList += ["Baking Powder"]
To insert a new value in a specific place use the insert(_:at:) method. Similarly, you remove an item from the array with the remove(at:)
method:
shoppingList.insert("Maple Syrup", at: 0)
// retrieve value
var firstItem = shoppingList[0]
// change value
shoppingList[0] = "Six eggs"
for item in shoppingList {
print(item)
}
Dictionaries
You can add a new item to a dictionary with subscript syntax. Use a new key of the appropriate type as the subscript index, and assign a new value of the appropriate type:
airports["LHR"] = "London"
// the airports dictionary now contains 3 items
airports["LHR"] = "London Heathrow"
// the value for "LHR" has been changed to "London Heathrow"
You can iterate over the key-value pairs in a dictionary with a for
–in
loop. Each item in the dictionary is returned as a (key, value)
tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration:
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// LHR: London Heathrow
// YYZ: Toronto Pearson
Control Flow
For-In Loops
You use the for
–in
loop to iterate over a sequence, such as items in an array, ranges of numbers, or characters in a string:
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
In some situations, you might not want to use closed ranges, which include both endpoints. In this case we are iterating the number of times that the variables value is set to:
let minutes = 60
for tickMark in 0..<minutes {
// render the tick mark each minute (60 times)
}
If you want to do the same as the above but only do it every 5 times, use the stride(from:to:by) function:
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
While Loops
A while
loop performs a set of statements until a condition becomes false
. These kinds of loops are best used when the number of iterations is not known before the first iteration begins. Swift provides two kinds of while
loops:
while
evaluates its condition at the start of each pass through the loop.repeat
–while
evaluates its condition at the end of each pass through the loop.
While
A while
loop starts by evaluating a single condition. If the condition is true
, a set of statements is repeated until the condition becomes false
.
while condition {
statements
}
Repeat-While
The repeat
–while
loop, performs a single pass through the loop block first, before considering the loop’s condition. It then continues to repeat the loop until the condition is false
.
repeat {
statements
} while condition
Conditional Statements
Switch Statements
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet")
case "z":
print("The last letter of the alphabet")
default:
print("Some other character")
}
You can also create a compound switch case, in which you test two or more possible values. For readability, a compound case can also be written over multiple lines. An example is below.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
When matching tuples in switch statements, and multiple matches are possible, the first matching case is always used.
let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
print("On an axis, \(distance) from the origin")
default:
print("Not on an axis")
}
// Prints "On an axis, 9 from the origin"
Control Transfer Statements
Swift has five control transfer statements.
continue
break
fallthrough
return
throw
Break
The break
statement can be used inside a switch
or loop statement when you want to terminate the execution of the switch
or loop statement earlier than would otherwise be the case.
Fallthrough
In Swift the switch
statement completes its execution as soon as the first matching case is completed. This is in contrast to C, where the switch statement runs through each possible case that does not have a break statement. The fallthrough
statement allows you to mimic the behavior in C and “fall through” to the next switch statement, even after you’ve found a matching statement.
Early Exit
A guard statement lets you write the code that’s typically executed without wrapping it in an else
block, and it lets you keep the code that handles a violated requirement next to the requirement. An example is below:
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
}
greet(person: ["name": "John"])
// Prints "Hello John!"
These notes are continued in Part 2 found here.
@joekotlan on X