Error Handling
-
A function indicates that it can throw an error by including the
throwskeyword in its declaration. When you call a function that can throw an error, you prepend thetrykeyword to the expression.func canThrowAnError() throws { // this function may or may not throw an error } -
When you call a function that can throw an error, you prepend the
trykeyword to the expression. -
Swift automatically propagates errors out of their current scope until they’re handled by a
catchclause.do { try canThrowAnError() // no error was thrown } catch { // an error was thrown } -
Example :
func makeASandwich() throws { // ... } do { try makeASandwich() eatASandwich() } catch SandwichError.outOfCleanDishes { washDishes() } catch SandwichError.missingIngredients(let ingredients) { buyGroceries(ingredients) }
precondition
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")
assert
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 isn't >= 0.
guard
func hit(enemy: Monster?, with weapon: Weapon) {
guard let enemy else { return }
if enemy.isAlive {
enemy.health -= weapon.damage
}
}
if let
-
Extended version:
let myNumber = Int(possibleNumber)
// Here, myNumber is an optional integer
if let myNumber = myNumber {
// Here, myNumber is a non-optional integer
print("My number is \(myNumber)")
}
// Prints "My number is 123"
-
Simplified version:
-
Because this kind of code is so common, you can use a shorter spelling to unwrap an optional value: Write just the name of the constant or variable that you’re unwrapping. The new, unwrapped constant or variable implicitly uses the same name as the optional value.
if let myNumber { print("My number is \(myNumber)") } // Prints "My number is 123" -
-
You can include as many optional bindings and Boolean conditions in a single
ifstatement as you need to, separated by commas. If any of the values in the optional bindings arenilor any Boolean condition evaluates tofalse, the wholeifstatement’s condition is considered to befalse. The followingifstatements are equivalent:
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// Prints "4 < 42 < 100"
-
Example :
func hit(enemy: Monster?, with weapon: Weapon) { if let enemy { if enemy.isAlive { enemy.health -= weapon.damage } } }-
“If the optional
Monsterreturned byenemycontains a value, then it is true".
func hit(enemy: Monster?, with weapon: Weapon) { if let new_enemy = enemy { if new_enemy.isAlive { new_enemy.health -= weapon.damage } } }-
“If the optional
Monsterreturned byenemycontains a value, set a new constant callednew_enemyto the value contained in the optional.”
-
Fallback
-
Another way to handle a missing value is to supply a default value using the nil-coalescing operator (
??). If the optional on the left of the??isn’tnil, that value is unwrapped and used. Otherwise, the value on the right of??is used. For example, the code below greets someone by name if one is specified, and uses a generic greeting when the name isnil.
let name: String? = nil
let greeting = "Hello, " + (name ?? "friend") + "!"
print(greeting)
// Prints "Hello, friend!"
Force Unwrapping
-
You can ignore the fact that the object might be nil, using the
!operator:var selected: String? func okPressed() { // I "know" 'selected' will never be null, let me use it. saveFile(selected!) } -
If it is
nil, it will crash at runtime, so!andfatalErrorare equivalent.let possibleNumber = "123" let convertedNumber = Int(possibleNumber) let number = convertedNumber! guard let number = convertedNumber else { fatalError("The number was invalid") }
Implicit Unwrap
-
You can think of an implicitly unwrapped optional as giving permission for the optional to be force-unwrapped if needed.
-
Usage :
-
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter.
-
An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a non-optional value, without the need to unwrap the optional value each time it’s accessed.
-
-
Cautions :
-
If an implicitly unwrapped optional is
niland you try to access its wrapped value, you’ll trigger a runtime error. -
The result is exactly the same as if you write an exclamation point to force unwrap a normal optional that doesn’t contain a value.
-
-
Creation :
-
You write an implicitly unwrapped optional by placing an exclamation point (
String!) rather than a question mark (String?) after the type that you want to make optional. -
Rather than placing an exclamation point after the optional’s name when you use it, you place an exclamation point after the optional’s type when you declare it.
-
-
Differences between Implicit and Explicit :
let possibleString: String? = "An optional string." let forcedString: String = possibleString! // Requires explicit unwrapping let assumedString: String! = "An implicitly unwrapped optional string." let implicitString: String = assumedString // Unwrapped automatically
Overflow
-
Crashes :
var score = Int.max score = score + 1 // Crashes due to overflow. -
Ignoring with
&(yolo operator) :var score = Int.max score = score &+ 1 // Does not crash, but overflows (the number flips and becomes negative).
Concurrency
var a = [1, 2, 3, 4, 5]
Task {
print(a.count)
}
a.append(10) // Gives a warning for trying to modify something in a "race condition".