Swift Guard Statement – Why you should use it

https://stackoverflow.com/a/35046681/3151712For-In Loops

You use the forin 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)!”)
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!

You can also iterate over a dictionary to access its key-value pairs. Each item in the dictionary is returned as a (key, value) tuple when the dictionary is iterated, and you can decompose the (key, value) tuple’s members as explicitly named constants for use within the body of the forin loop. In the code example below, the dictionary’s keys are decomposed into a constant called animalName, and the dictionary’s values are decomposed into a constant called legCount.

let numberOfLegs = [“spider”: 8, “ant”: 6, “cat”: 4]
for (animalName, legCount) in numberOfLegs {
   print(“(animalName)s have (legCount) legs”)
}
// ants have 6 legs
// spiders have 8 legs
// cats have 4 legs

for index in 1…5 {
   print(“(index) times 5 is (index * 5)”)
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25

If you don’t need each value from a sequence, you can ignore the values by using an underscore in place of a variable name.

let base = 3
let power = 10
var answer = 1
for _ in 1…power {
   answer *= base
}
print(“(base) to the power of (power) is (answer)”)
// Prints “3 to the power of 10 is 59049”

let minutes = 60
for tickMark in 0..<minutes {
   // render the tick mark each minute (60 times)
}

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)
}

Closed ranges are also available, by using stride(from:through:by:) instead:

let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
   // render the tick mark every 3 hours (3, 6, 9, 12)
}

While Loops

  • while evaluates its condition at the start of each pass through the loop.
  • repeatwhile 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 square < finalSquare {
   // roll the dice
   
}

Repeat-While

The other variation of the while loop, known as the repeatwhile 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 {
   // move up or down for a snake or ladder
  
} while square < finalSquare

Conditional Statements

If

if temperatureInFahrenheit <= 32 {
   print(“It’s very cold. Consider wearing a scarf.”)
} else if temperatureInFahrenheit >= 86 {
   print(“It’s really warm. Don’t forget to wear sunscreen.”)
} else {
   print(“It’s not that cold. Wear a t-shirt.”)
}
// Prints “It’s really warm. Don’t forget to wear sunscreen.”

Switch

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”)
}
// Prints “The last letter of the alphabet”

No Implicit Fallthrough

In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit breakstatement.

NOTE

Although break is not required in Swift, you can use a break statement to match and ignore a particular case or to break out of a matched case before that case has completed its execution.

The body of each case must contain at least one executable statement. It is not valid to write the following code, because the first case is empty:

let anotherCharacter: Character = “a”
switch anotherCharacter {
case “a”: // Invalid, the case has an empty body
case “A”:
   print(“The letter A”)
default:
   print(“Not the letter A”)
}
// This will report a compile-time error.

To make a switch with a single case that matches both "a" and "A", combine the two values into a compound case, separating the values with commas.

let anotherCharacter: Character = “a”
switch anotherCharacter {
case “a”, “A”:
   print(“The letter A”)
default:
   print(“Not the letter A”)
}
// Prints “The letter A”

Interval Matching

let approximateCount = 62
let countedThings = “moons orbiting Saturn”
let naturalCount: String
switch approximateCount {
case 0:
   naturalCount = “no”
case 1..<5:
   naturalCount = “a few”
case 5..<12:
   naturalCount = “several”
case 12..<100:
   naturalCount = “dozens of”
case 100..<1000:
   naturalCount = “hundreds of”
default:
   naturalCount = “many”
}
print(“There are (naturalCount) (countedThings).”)
// Prints “There are dozens of moons orbiting Saturn.”

Tuples

You can use tuples to test multiple values in the same switch statement. use the underscore character (_), also known as the wildcard pattern, to match any possible value.

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
   print(“(somePoint) is at the origin”)
case (_, 0):
   print(“(somePoint) is on the x-axis”)
case (0, _):
   print(“(somePoint) is on the y-axis”)
case (-2…2, -2…2):
   print(“(somePoint) is inside the box”)
default:
   print(“(somePoint) is outside of the box”)
}
// Prints “(1, 1) is inside the box”

n fact, the point (0, 0) could match all four of the cases in this example. However, if multiple matches are possible, the first matching case is always used. The point (0, 0) would match case (0, 0) first, and so all other matching cases would be ignored.

Value Bindings

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
   print(“on the x-axis with an x value of (x)”)
case (0, let y):
   print(“on the y-axis with a y value of (y)”)
case let (x, y):
   print(“somewhere else at ((x), (y))”)
}
// Prints “on the x-axis with an x value of 2”

After the temporary constants are declared, they can be used within the case’s code block. 

This switch statement does not have a default case. The final case, case let (x, y), declares a tuple of two placeholder constants that can match any value. Because anotherPoint is always a tuple of two values, this case matches all possible remaining values, and a default case is not needed to make the switch statement exhaustive.

Where

A switch case can use a where clause to check for additional conditions.

let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
   print(“((x), (y)) is on the line x == y”)
case let (x, y) where x == -y:
   print(“((x), (y)) is on the line x == -y”)
case let (x, y):
   print(“((x), (y)) is just some arbitrary point”)
}
// Prints “(1, -1) is on the line x == -y”

Compound Cases

Multiple switch cases that share the same body can be combined by writing several patterns after case, with a comma between each of the patterns.

let someCharacter: Character = “e”
switch someCharacter {
case “a”, “e”, “i”, “o”, “u”:
   print(“(someCharacter) is a vowel”)
case “b”, “c”, “d”, “f”, “g”, “h”, “j”, “k”, “l”, “m”,
    “n”, “p”, “q”, “r”, “s”, “t”, “v”, “w”, “x”, “y”, “z”:
   print(“(someCharacter) is a consonant”)
default:
   print(“(someCharacter) is not a vowel or a consonant”)
}
// Prints “e is a vowel”

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

  • continue
  • break
  • fallthrough
  • return
  • throw

Continue

The continue statement tells a loop to stop what it is doing and start again at the beginning of the next iteration through the loop.

let puzzleInput = “great minds think alike”
var puzzleOutput = “”
let charactersToRemove: [Character] = [“a”, “e”, “i”, “o”, “u”, “ ”]
for character in puzzleInput {
   if charactersToRemove.contains(character) {
       continue
   } else {
       puzzleOutput.append(character)
   }
}
print(puzzleOutput)
// Prints “grtmndsthnklk”

Break

The break statement ends execution of an entire control flow statement immediately. 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.

Break in a Loop Statement

When used inside a loop statement, break ends the loop’s execution immediately and transfers control to the code after the loop’s closing brace (}). No further code from the current iteration of the loop is executed, and no further iterations of the loop are started.

Break in a Switch Statement

When used inside a switch statement, break causes the switch statement to end its execution immediately and to transfer control to the code after the switch statement’s closing brace (}).

Fallthrough

In Swift,the entire switch statement completes its execution as soon as the first matching case is completed. By contrast, C requires you to insert an explicit break statement at the end of every switch case to prevent fallthrough

let integerToDescribe = 5
var description = “The number (integerToDescribe) is”
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
   description += “ a prime number, and also”
   fallthrough
default:
   description += “ an integer.”
}
print(description)
// Prints “The number 5 is a prime number, and also an integer.”

NOTE

The fallthrough keyword simply causes code execution to move directly to the statements inside the next case (or default case) block, as in C’s standard switch statement behavior.

Labeled Statements

gameLoop: while square != finalSquare {
   diceRoll += 1
   if diceRoll == 7 { diceRoll = 1 }
   switch square + diceRoll {
   case finalSquare:
       // diceRoll will move us to the final square, so the game is over
       break gameLoop
   case let newSquare where newSquare > finalSquare:
       // diceRoll will move us beyond the final square, so roll again
       continue gameLoop
   default:
       // this is a valid move, so find out its effect
       square += diceRoll
       square += board[square]
   }
}
print(“Game over!”)

Early Exit

A guard statement, like an if statement, executes statements depending on the Boolean value of an expression. You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed. Unlike an if statement, a guard statement always has an else clause—the code inside the else clause is executed if the condition is not true.

func greet(person: [String: String]) {
   guard let name = person[“name”] else {
       return
   }
   
   print(“Hello (name)!”)
   
   guard let location = person[“location”] else {
       print(“I hope the weather is nice near you.”)
       return
   }
   
   print(“I hope the weather is nice in (location).”)
}
greet(person: [“name”: “John”])
// Prints “Hello John!”
// Prints “I hope the weather is nice near you.”
greet(person: [“name”: “Jane”, “location”: “Cupertino”])
// Prints “Hello Jane!”
// Prints “I hope the weather is nice in Cupertino.”

If the guard statement’s condition is met, code execution continues after the guard statement’s closing brace. Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that the guard statement appears in.

If that condition is not met, the code inside the else branch is executed. That branch must transfer control to exit the code block in which the guard statement appears. It can do this with a control transfer statement such as return, break, continue, or throw, or it can call a function or method that doesn’t return, such as fatalError(_:file:line:).

참고

ref) https://ericcerney.com/swift-guard-statement/

optional binding ref) https://stackoverflow.com/a/35046681/3151712

Checking API Availability

Swift has built-in support for checking API availability, which ensures that you don’t accidentally use APIs that are unavailable on a given deployment target.

You use an availability condition in an if or guard statement to conditionally execute a block of code.

if #available(iOS 10, macOS 10.12, *) {
   // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
   // Fall back to earlier iOS and macOS APIs
}

if #available(platform name version, …, *) {
   statements to execute if the APIs are available
} else {
   fallback statements to execute if the APIs are unavailable
}

Collection Types

image

swift에서 collection들은 타입을 지정하고 그 타입의 것들만 받아들이게 된다.

NOTE

Swift’s array, set, and dictionary types are implemented as generic collections. For more on generic types and collections, see Generics.

Mutability of Collections

If you create an array, a set, or a dictionary, and assign it to a variable, the collection that is created will be mutable. This means that you can change (or mutate) the collection after it’s created by adding, removing, or changing items in the collection. If you assign an array, a set, or a dictionary to a constant, that collection is immutable, and its size and contents cannot be changed.

Arrays

Array Type Shorthand Syntax

만드는법

  • Array<Element>, where Element is the type of values the array is allowed to store. 
  • [Element]

Creating an Empty Array

var someInts = [Int]()
print(“someInts is of type [Int] with (someInts.count) items.”)
// Prints “someInts is of type [Int] with 0 items.”

Alternatively, if the context already provides type information, such as a function argument or an already typed variable or constant, you can create an empty array with an empty array literal, which is written as [] (an empty pair of square brackets):

someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type [Int]

Creating an Array with a Default Value

 creating an array of a certain size with all of its values set to the same default value. 

var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]

Creating an Array by Adding Two Arrays Together

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

Creating an Array with an Array Literal

[value 1, value 2, value 3]

var shoppingList: [String] = [“Eggs”, “Milk”]
// shoppingList has been initialized with two initial items

Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization of shoppingList could have been written in a shorter form instead:

var shoppingList = [“Eggs”, “Milk”]

Accessing and Modifying an Array

You access and modify an array through its methods and properties, or by using subscript syntax.

print(“The shopping list contains (shoppingList.count) items.”)
// Prints “The shopping list contains 2 items.”

if shoppingList.isEmpty {
   print(“The shopping list is empty.”)
} else {
   print(“The shopping list is not empty.”)
}
// Prints “The shopping list is not empty.”

shoppingList.append(“Flour”)
// shoppingList now contains 3 items, and someone is making pancakes

Alternatively

shoppingList += [“Baking Powder”]
// shoppingList now contains 4 items
shoppingList += [“Chocolate Spread”, “Cheese”, “Butter”]
// shoppingList now contains 7 items

Retrieve a value from the array by using subscript syntax, passing the index of the value you want to retrieve within square brackets immediately after the name of the array:

var firstItem = shoppingList[0]
// firstItem is equal to “Eggs”

NOTE

Arrays in Swift are always zero-indexed.

subscript syntax to change an existing value at a given index:

shoppingList[0] = “Six eggs”
// the first item in the list is now equal to “Six eggs” rather than “Eggs”

You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces "Chocolate Spread", "Cheese", and "Butter" with "Bananas" and "Apples":

shoppingList[4…6] = [“Bananas”, “Apples”]
// shoppingList now contains 6 items

insert(_:at:) method:

shoppingList.insert(“Maple Syrup”, at: 0)
// shoppingList now contains 7 items
// “Maple Syrup” is now the first item in the list

This call to the insert(_:at:) method inserts a new item with a value of "Maple Syrup" at the very beginning of the shopping list, indicated by an index of 0.

remove(at:) method

let mapleSyrup = shoppingList.remove(at: 0)
// the item that was at index 0 has just been removed
// shoppingList now contains 6 items, and no Maple Syrup
// the mapleSyrup constant is now equal to the removed “Maple Syrup” string

NOTE

If you try to access or modify a value for an index that is outside of an array’s existing bounds, you will trigger a runtime error. You can check that an index is valid before using it by comparing it to the array’s countproperty. The largest valid index in an array is count - 1 because arrays are indexed from zero—however, when count is 0 (meaning the array is empty), there are no valid indexes.

removeLast() method 

let apples = shoppingList.removeLast()
// the last item in the array has just been removed
// shoppingList now contains 5 items, and no apples
// the apples constant is now equal to the removed “Apples” string

Iterating Over an Array

for item in shoppingList {
   print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas

If you need the integer index of each item as well as its value, use the enumerated() method to iterate over the array instead. For each item in the array, the enumerated() method returns a tuple composed of an integer and the item. The integers start at zero and count up by one for each item; if you enumerate over a whole array, these integers match the items’ indices. You can decompose the tuple into temporary constants or variables as part of the iteration:

for (index, value) in shoppingList.enumerated() {
   print(“Item (index + 1): (value)”)
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas

Sets

A set stores distinct values of the same type in a collection with no defined ordering.

NOTE

Swift’s Set type is bridged to Foundation’s NSSet class.

Hash Values for Set Types

A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that is the same for all objects that compare equally, such that if a == b, it follows that a.hashValue == b.hashValue.

All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default, and can be used as set value types or dictionary key types. Enumeration case values without associated values (as described in Enumerations) are also hashable by default.

NOTE

You can use your own custom types as set value types or dictionary key types by making them conform to the Hashable protocol from Swift’s standard library. Types that conform to the Hashable protocol must provide a gettable Int property called hashValue. The value returned by a type’s hashValue property is not required to be the same across different executions of the same program, or in different programs.

Because the Hashable protocol conforms to Equatable, conforming types must also provide an implementation of the equals operator (==). The Equatable protocol requires any conforming implementation of == to be an equivalence relation. That is, an implementation of == must satisfy the following three conditions, for all values a, b, and c:

  • a == a (Reflexivity)
  • a == b implies b == a (Symmetry)
  • a == b && b == c implies a == c (Transitivity)

Set Type Syntax

The type of a Swift set is written as Set<Element>, where Element is the type that the set is allowed to store. Unlike arrays, sets do not have an equivalent shorthand form.

Creating and Initializing an Empty Set

var letters = Set<Character>()
print(“letters is of type Set<Character> with (letters.count) items.”)
// Prints “letters is of type Set<Character> with 0 items.”

NOTE

The type of the letters variable is inferred to be Set<Character>, from the type of the initializer.

Alternatively, if the context already provides type information, such as a function argument or an already typed variable or constant, you can create an empty set with an empty array literal:

letters.insert(“a”)
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set<Character> 위에서 이미 character라고 정해졌기 때문에 여기서 또 명시할필요는 없다.

Creating a Set with an Array Literal

var favoriteGenres: Set<String> = [“Rock”, “Classical”, “Hip hop”]
// favoriteGenres has been initialized with three initial items

The favoriteGenres variable is declared as “a set of String values”, written as Set<String>. Because this particular set has specified a value type of String.

A set type cannot be inferred from an array literal alone, so the type Set must be explicitly declared. However, because of Swift’s type inference, you don’t have to write the type of the set if you’re initializing it with an array literal containing values of the same type. (데이터타입은 명시하지 않아도 되지만  set이라고는 명시해야 된다.)

var favoriteGenres: Set = [“Rock”, “Classical”, “Hip hop”]

Accessing and Modifying a Set

You access and modify a set through its methods and properties.

count property:

print(“I have (favoriteGenres.count) favorite music genres.”)
// Prints “I have 3 favorite music genres.”

isEmpty property

if favoriteGenres.isEmpty {
   print(“As far as music goes, I’m not picky.”)
} else {
   print(“I have particular music preferences.”)
}
// Prints “I have particular music preferences.”

insert(_:) method:

favoriteGenres.insert(“Jazz”)
// favoriteGenres now contains 4 items

remove(_:) method, which removes the item if it’s a member of the set, and returns the removed value, or returns nil if the set did not contain it. 

all items in a set can be removed with its removeAll() method.

if let removedGenre = favoriteGenres.remove(“Rock”) {
   print(“(removedGenre)? I’m over it.”)
} else {
   print(“I never much cared for that.”)
}
// Prints “Rock? I’m over it.”

contains(_:) method.

if favoriteGenres.contains(“Funk”) {
   print(“I get up on the good foot.”)
} else {
   print(“It’s too funky in here.”)
}
// Prints “It’s too funky in here.”

Iterating Over a Set

for genre in favoriteGenres {
   print(“(genre)”)
}
// Jazz
// Hip hop
// Classical

Swift’s Set type does not have a defined ordering. To iterate over the values of a set in a specific order, use the sorted() method, which returns the set’s elements as an array sorted using the < operator.

for genre in favoriteGenres.sorted() {
   print(“(genre)”)
}
// Classical
// Hip hop
// Jazz

Performing Set Operations

Fundamental Set Operations

image
  • Use the intersection(_:) method to create a new set with only the values common to both sets.
  • Use the symmetricDifference(_:) method to create a new set with values in either set, but not both.
  • Use the union(_:) method to create a new set with all of the values in both sets.
  • Use the subtracting(_:) method to create a new set with values not in the specified set.

let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]

Set Membership and Equality

Set a is a superset of set b, because a contains all elements in b. Conversely, set b is a subset of set a.

image

Use the “is equal” operator (==) to determine whether two sets contain all of the same values.

Use the isSubset(of:) method to determine whether all of the values of a set are contained in the specified set.

Use the isSuperset(of:) method to determine whether a set contains all of the values in a specified set.

Use the isStrictSubset(of:) or isStrictSuperset(of:) methods to determine whether a set is a subset or superset, but not equal to, a specified set.

Use the isDisjoint(with:) method to determine whether two sets have no values in common.

let houseAnimals: Set = [“🐶”, “🐱”]
let farmAnimals: Set = [“🐮”, “🐔”, “🐑”, “🐶”, “🐱”]
let cityAnimals: Set = [“🐦”, “🐭”]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true

Dictionaries

A dictionary stores associations between keys of the same type and values of the same type in a collection with no defined ordering. Each value is associated with a unique key.

NOTE

Swift’s Dictionary type is bridged to Foundation’s NSDictionary class.

Dictionary Type Shorthand Syntax

Dictionary<Key, Value>

NOTE

A dictionary Key type must conform to the Hashable protocol, like a set’s value type.

You can also write the type of a dictionary in shorthand form as [Key: Value].

Creating an Empty Dictionary

var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary

If the context already provides type information, you can create an empty dictionary with an empty dictionary literal, which is written as [:] (a colon inside a pair of square brackets):

namesOfIntegers[16] = “sixteen”
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]

Accessing and Modifying a Dictionary

You access and modify a dictionary through its methods and properties, or by using subscript syntax.

read-only count property:

print(“The airports dictionary contains (airports.count) items.”)
// Prints “The airports dictionary contains 2 items.”

isEmpty property

if airports.isEmpty {
   print(“The airports dictionary is empty.”)
} else {
   print(“The airports dictionary is not empty.”)
}
// Prints “The airports dictionary is not empty.”

assign a new value

airports[“LHR”] = “London”
// the airports dictionary now contains 3 items

change the value

airports[“LHR”] = “London Heathrow”
// the value for “LHR” has been changed to “London Heathrow”

updateValue(_:forKey:) method to set or update the value for a particular key. updateValue(_:forKey:) method sets a value for a key if none exists, or updates the value if that key already exists. Unlike a subscript, however, the updateValue(_:forKey:) method returns the old value after performing an update.

The updateValue(_:forKey:) method returns an optional value of the dictionary’s value type. For a dictionary that stores String values, for example, the method returns a value of type String?, or “optional String”. This optional value contains the old value for that key if one existed before the update, or nil if no value existed:

if let oldValue = airports.updateValue(“Dublin Airport”, forKey: “DUB”) {
   print(“The old value for DUB was (oldValue).”)
}
// Prints “The old value for DUB was Dublin.”

if let airportName = airports[“DUB”] {
   print(“The name of the airport is (airportName).”)
} else {
   print(“That airport is not in the airports dictionary.”)
}
// Prints “The name of the airport is Dublin Airport.”

remove a key-value pair from a dictionary by assigning a value of nil for that key:

airports[“APL”] = “Apple International”
// “Apple International” is not the real airport for APL, so delete it

airports[“APL”] = nil
// APL has now been removed from the dictionary

Alternatively, remove a key-value pair from a dictionary with the removeValue(forKey:) method. This method removes the key-value pair if it exists and returns the removed value, or returns nil if no value existed:

if let removedValue = airports.removeValue(forKey: “DUB”) {
   print(“The removed airport’s name is (removedValue).”)
} else {
   print(“The airports dictionary does not contain a value for DUB.”)
}
// Prints “The removed airport’s name is Dublin Airport.”

Iterating Over a Dictionary

You can iterate over the key-value pairs in a dictionary with a forin 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)”)
}
// YYZ: Toronto Pearson
// LHR: London Heathrow

keys and values properties:

for airportCode in airports.keys {
   print(“Airport code: (airportCode)”)
}
// Airport code: YYZ
// Airport code: LHR
for airportName in airports.values {
   print(“Airport name: (airportName)”)
}
// Airport name: Toronto Pearson
// Airport name: London Heathrow

let airportCodes = [String](airports.keys)
// airportCodes is [“YYZ”, “LHR”]

let airportNames = [String](airports.values)
// airportNames is [“Toronto Pearson”, “London Heathrow”]

Swift’s Dictionary type does not have a defined ordering. To iterate over the keys or values of a dictionary in a specific order, use the sorted() method on its keys or values property.

String concatenation is as simple as combining two strings with the + operator, and string mutability is managed by choosing between a constant or a variable.Every string is composed of encoding-independent Unicode characters.

NOTE

Swift’s String type is bridged with Foundation’s NSString class. Foundation also extends String to expose methods defined by NSString. This means, if you import Foundation, you can access those NSStringmethods on String without casting.

String Literals

Use a string literal as an initial value for a constant or variable:

let someString = “Some string literal value”

Multiline String Literals

let quotation = “”“
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.”
“"”

When your source code includes a line break inside of a multiline string literal, that line break also appears in the string’s value. 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.”
“"”

To make a multiline string literal that begins or ends with a line feed, write a blank line as the first or last line. For example:

let lineBreaks = ”“”

This string starts with a line break.
It also ends with a line break.

“”“

A multiline string can be indented to match the surrounding code. The whitespace before the closing quotation marks (""") tells Swift what whitespace to ignore before all of the other lines. However, if you write whitespace at the beginning of a line in addition to what’s before the closing quotation marks, that whitespace is included.

image

Special Characters in String Literals

String literals can include the following special characters:

  • The escaped special characters (null character), \ (backslash), t (horizontal tab), n (line feed), r(carriage return), " (double quotation mark) and ' (single quotation mark)
  • An arbitrary Unicode scalar, written as u{n}, where n is a 1–8 digit hexadecimal number with a value equal to a valid Unicode code point

Because multiline string literals use three double quotation marks instead of just one, you can include a double quotation mark (") inside of a multiline string literal without escaping it.

Initializing an Empty String

var emptyString = ”“               // empty string literal
var anotherEmptyString = String()  // initializer syntax
// these two strings are both empty, and are equivalent to each other

Find out whether a String value is empty by checking its Boolean isEmpty property:

if emptyString.isEmpty {
   print("Nothing to see here”)
}
// Prints “Nothing to see here”

String Mutability

var variableString = “Horse”
variableString += “ and carriage”
// variableString is now “Horse and carriage”

let constantString = “Highlander”
constantString += “ and another Highlander”
// this reports a compile-time error – a constant string cannot be modified

Strings Are Value Types

Swift’s String type is a value type. If you create a new String value, that String value is copied when it’s passed to a function or method, or when it’s assigned to a constant or variable. In each case, a new copy of the existing String value is created, and the new copy is passed or assigned, not the original version. (copy by value, not reference)

Working with Characters

for character in “Dog!🐶” {
   print(character)
}
// D
// o
// g
// !
// 🐶

let exclamationMark: Character = “!”

캐릭터 배열을 통해 string 만드는법

let catCharacters: [Character] = [“C”, “a”, “t”, “!”, “🐱”]
let catString = String(catCharacters)
print(catString)
// Prints “Cat!🐱”

Concatenating Strings and Characters

let string1 = “hello”

let string2 = “ there”

var welcome = string1 + string2

// welcome now equals “hello there”

var instruction = “look over”
instruction += string2
// instruction now equals “look over there”

let exclamationMark: Character = “!”
welcome.append(exclamationMark)
// welcome now equals “hello there!”

NOTE

You can’t append a String or Character to an existing Character variable, because a Character value must contain a single character only.

String Interpolation

Each item that you insert into the string literal is wrapped in a pair of parentheses, prefixed by a backslash ():

let multiplier = 3
let message = “(multiplier) times 2.5 is (Double(multiplier) * 2.5)”
// message is “3 times 2.5 is 7.5”

Unicode

Swift’s String and Character types are fully Unicode-compliant.

Unicode Scalars

NOTE

A Unicode scalar is any Unicode code point in the range U+0000 to U+D7FF inclusive or U+E000 to U+10FFFFinclusive. Unicode scalars don’t include the Unicode surrogate pair code points, which are the code points in the range U+D800 to U+DFFF inclusive.

Accessing and Modifying a String

You access and modify a string through its methods and properties, or by using subscript syntax.

String Indices

Each String value has an associated index type, String.Index, which corresponds to the position of each Character in the string.

As mentioned above, different characters can require different amounts of memory to store, so in order to determine which Character is at a particular position, you must iterate over each Unicode scalar from the start or end of that String. For this reason, Swift strings can’t be indexed by integer values.

Use the startIndex property to access the position of the first Character of a String. The endIndex property is the position after the last character in a String. As a result, the endIndex property isn’t a valid argument to a string’s subscript. If a String is empty, startIndex and endIndex are equal.

You access the indices before and after a given index using the index(before:) and index(after:) methods of String. To access an index farther away from the given index, you can use the index(_:offsetBy:) method instead of calling one of these methods multiple times.

let greeting = “Guten Tag!”
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a

greeting[greeting.endIndex] // Error
greeting.index(after: greeting.endIndex) // Error

Use the indices property to access all of the indices of individual characters in a string.

for index in greeting.indices {
   print(“(greeting[index]) ”, terminator: “”)
}
// Prints “G u t e n   T a g ! ”

NOTE

You can use the startIndex and endIndex properties and the index(before:), index(after:), and index(_:offsetBy:) methods on any type that conforms to the Collection protocol. This includes String, as shown here, as well as collection types such as Array, Dictionary, and Set.

(string이나 array나 dictionary나 set은 같은 방법으로 접근 가능하다는 이야기)

Inserting and Removing

insert(_:at:) 

insert(contentsOf:at:) method.

var welcome = “hello”
welcome.insert(“!”, at: welcome.endIndex)
// welcome now equals “hello!”
welcome.insert(contentsOf: “ there”, at: welcome.index(before: welcome.endIndex))
// welcome now equals “hello there!”

remove(at:)

removeSubrange(_:)

welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals “hello there”

let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex

welcome.removeSubrange(range)
// welcome now equals “hello”

NOTE

You can use the insert(_:at:), insert(contentsOf:at:), remove(at:), and removeSubrange(_:) methods on any type that conforms to the RangeReplaceableCollection protocol. This includes String, as shown here, as well as collection types such as Array, Dictionary, and Set.

(string이나 array나 dictionary나 set은 같은 방법으로 접근 가능하다는 이야기)

Substrings

When you get a substring from a string—for example, using a subscript or a method like prefix(_:)—the result is an instance of Substring, not another string. Substrings in Swift have most of the same methods as strings, which means you can work with substrings the same way you work with strings. However, unlike strings, you use substrings for only a short amount of time while performing actions on a string. When you’re ready to store the result for a longer time, you convert the substring to an instance of String

let greeting = “Hello, world!”
let index = greeting.index(of: “,”) ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is “Hello”
// Convert the result to a String for long-term storage.
let newString = String(beginning)

NOTE

Both String and Substring conform to the StringProtocol protocol, which means it’s often convenient for string-manipulation functions to accept a StringProtocol value. You can call such functions with either a String or Substring value.

Comparing Strings

Swift provides three ways to compare textual values: string and character equality, prefix equality, and suffix equality.

String and Character Equality

String and character equality is checked with the “equal to” operator (==) and the “not equal to” operator (!=), as described in Comparison Operators:

let quotation = “We’re a lot alike, you and I.”
let sameQuotation = “We’re a lot alike, you and I.”
if quotation == sameQuotation {
   print(“These two strings are considered equal”)
}
// Prints “These two strings are considered equal”

Two String values (or two Character values) are considered equal if their extended grapheme clusters are canonically equivalent. Extended grapheme clusters are canonically equivalent if they have the same linguistic meaning and appearance, even if they’re composed from different Unicode scalars behind the scenes.

Prefix and Suffix Equality

To check whether a string has a particular string prefix or suffix, call the string’s hasPrefix(_:) and hasSuffix(_:) methods, both of which take a single argument of type String and return a Boolean value.

let romeoAndJuliet = [
   "Act 1 Scene 1: Verona, A public place",
   "Act 1 Scene 2: Capulet’s mansion",
   "Act 1 Scene 3: A room in Capulet’s mansion",
   "Act 1 Scene 4: A street outside Capulet’s mansion",
   "Act 1 Scene 5: The Great Hall in Capulet’s mansion",
   "Act 2 Scene 1: Outside Capulet’s mansion",
   "Act 2 Scene 2: Capulet’s orchard",
   "Act 2 Scene 3: Outside Friar Lawrence’s cell",
   "Act 2 Scene 4: A street in Verona",
   "Act 2 Scene 5: Capulet’s mansion",
   "Act 2 Scene 6: Friar Lawrence’s cell"
]

var act1SceneCount = 0
for scene in romeoAndJuliet {
   if scene.hasPrefix(“Act 1 ”) {
       act1SceneCount += 1
   }
}
print(“There are (act1SceneCount) scenes in Act 1”)
// Prints “There are 5 scenes in Act 1”

var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
   if scene.hasSuffix(“Capulet’s mansion”) {
       mansionCount += 1
   } else if scene.hasSuffix(“Friar Lawrence’s cell”) {
       cellCount += 1
   }
}
print(“(mansionCount) mansion scenes; (cellCount) cell scenes”)
// Prints “6 mansion scenes; 2 cell scenes”

Unicode Representations of Strings

When a Unicode string is written to a text file or some other storage, the Unicode scalars in that string are encoded in one of several Unicode-defined encoding forms. Each form encodes the string in small chunks known as code units. These include the UTF-8 encoding form (which encodes a string as 8-bit code units), the UTF-16 encoding form (which encodes a string as 16-bit code units), and the UTF-32 encoding form (which encodes a string as 32-bit code units).

Swift provides several different ways to access Unicode representations of strings. You can iterate over the string with a forin statement, to access its individual Character values as Unicode extended grapheme clusters. This process is described in Working with Characters.

Alternatively, access a String value in one of three other Unicode-compliant representations:

  • A collection of UTF-8 code units (accessed with the string’s utf8 property)
  • A collection of UTF-16 code units (accessed with the string’s utf16 property)
  • A collection of 21-bit Unicode scalar values, equivalent to the string’s UTF-32 encoding form (accessed with the string’s unicodeScalars property)

(unicode라고 하더라도 하나의  character가 가지는 크기에 따라 위에 같이 나뉘게된다. 그렇지만  ascii가 차지하는것은 같은크기 )

let dogString = “Dog‼🐶”

for codeUnit in dogString.utf8 {
   print(“(codeUnit) ”, terminator: “”)
}
print(“”)
// Prints “68 111 103 226 128 188 240 159 144 182 ”

for codeUnit in dogString.utf16 {
   print(“(codeUnit) ”, terminator: “”)
}
print(“”)
// Prints “68 111 103 8252 55357 56374 ”

for scalar in dogString.unicodeScalars {
   print(“(scalar.value) ”, terminator: “”)
}
print(“”)
// Prints “68 111 103 8252 128054 ”

for scalar in dogString.unicodeScalars {
   print(“(scalar) ”)
}
// D
// o
// g
// ‼
// 🐶

Assignment Operator

let b = 10
var a = 5
a = b
// a is now equal to 10

let (x, y) = (1, 2)
// x is equal to 1, and y is equal to 2

the assignment operator in Swift does not itself return a value. The following statement is not valid.

if x = y {
   // This is not valid, because x = y does not return a value.
}

Arithmetic Operators

Swift supports the four standard arithmetic operators for all number types:

  • Addition (+)
  • Subtraction (-)
  • Multiplication (*)
  • Division (/)

1 + 2       // equals 3
5 – 3       // equals 2
2 * 3       // equals 6
10.0 / 2.5  // equals 4.0

the Swift arithmetic operators don’t allow values to overflow by default. You can opt in to value overflow behavior by using Swift’s overflow operators (such as a &+ b)

The addition operator is also supported for String concatenation:

“hello, ” + “world”  // equals “hello, world”

Remainder Operator

The remainder operator (a % b)

9 % 4    // equals 1

-9 % 4   // equals -1

The sign of b is ignored for negative values of b. This means that a % b and a % -b always give the same answer.

Unary Minus Operator

let three = 3
let minusThree = -three       // minusThree equals -3
let plusThree = -minusThree   // plusThree equals 3, or “minus minus three”

Unary Plus Operator

let minusSix = -6
let alsoMinusSix = +minusSix  // alsoMinusSix equals -6

the unary plus operator doesn’t actually do anything.

Compound Assignment Operators

var a = 1
a += 2
// a is now equal to 3

NOTE

The compound assignment operators don’t return a value. For example, you can’t write let b = a += 2.

Comparison Operators

  • Equal to (a == b)
  • Not equal to (a != b)
  • Greater than (a > b)
  • Less than (a < b)
  • Greater than or equal to (a >= b)
  • Less than or equal to (a <= b)

NOTE

Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance.

Each of the comparison operators returns a Bool value to indicate whether or not the statement is true:

1 == 1   // true because 1 is equal to 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.

(1, “zebra”) < (2, “apple”)   // true because 1 is less than 2; “zebra” and “apple” are not compared
(3, “apple”) < (3, “bird”)    // true because 3 is equal to 3, and “apple” is less than “bird”
(4, “dog”) == (4, “dog”)      // true because 4 is equal to 4, and “dog” is equal to “dog”

In the example above, you can see the left-to-right comparison behavior on the first line. Because 1 is less than 2, (1, "zebra") is considered less than (2, "apple"), regardless of any other values in the tuples. It doesn’t matter that "zebra" isn’t less than "apple", because the comparison is already determined by the tuples’ first elements. However, when the tuples’ first elements are the same, their second elements arecompared—this is what happens on the second and third line.

Tuples can be compared with a given operator only if the operator can be applied to each value in the respective tuples. For example, as demonstrated in the code below, you can compare two tuples of type (String, Int) because both String and Int values can be compared using the < operator. In contrast, two tuples of type (String, Bool) can’t be compared with the < operator because the < operator can’t be applied to Bool values.

(“blue”, -1) < (“purple”, 1)        // OK, evaluates to true
(“blue”, false) < (“purple”, true)  // Error because < can’t compare Boolean values

NOTE

The Swift standard library includes tuple comparison operators for tuples with fewer than seven elements. To compare tuples with seven or more elements, you must implement the comparison operators yourself.

Ternary Conditional Operator

question ? answer1 : answer2

와 아래는 같은내용

if question {
   answer1
} else {
   answer2
}

Nil-Coalescing Operator

The nil-coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.

a ?? b  는 아래돠 같은 내용

a != nil ? a! : b

NOTE

If the value of a is non-nil, the value of b is not evaluated. This is known as short-circuit evaluation.

Range Operators

closed range operator

a...b defines a range that runs from a to b, and includes the values a and b

for index in 1…5 {
   print(“(index) times 5 is (index * 5)”)
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25

Half-Open Range Operator

a..<b defines a range that runs from a to b, but doesn’t include b

Half-open ranges are particularly useful when you work with zero-based lists such as arrays. 

let names = [“Anna”, “Alex”, “Brian”, “Jack”]
let count = names.count
for i in 0..<count {
   print(“Person (i + 1) is called (names[i])”)
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack

One-Sided Ranges

for name in names[2…] {
   print(name)
}
// Brian
// Jack

for name in names[…2] {
   print(name)
}
// Anna
// Alex
// Brian

for name in names[..<2] {
   print(name)
}
// Anna
// Alex

let range = …5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true

Logical Operators

  • Logical NOT (!a)
  • Logical AND (a && b)
  • Logical OR (a || b)

Logical NOT Operator

The logical NOT operator (!a) inverts a Boolean value so that true becomes false, and false becomes true.

Logical AND Operator

let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
   print(“Welcome!”)
} else {
   print(“ACCESS DENIED”)
}
// Prints “ACCESS DENIED”

Logical OR Operator

let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
   print(“Welcome!”)
} else {
   print(“ACCESS DENIED”)
}
// Prints “Welcome!”

Integers

Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. An 8-bit unsigned integer is of type UInt8.

let minValue = UInt8.min  // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max  // maxValue is equal to 255, and is of type UInt8

Swift provides integer type, Int, which has the same size as the current platform’s native word size

On a 32-bit platform, Int is the same size as Int32.

On a 64-bit platform, Int is the same size as Int64.

On a 32-bit platform, UInt is the same size as UInt32.

On a 64-bit platform, UInt is the same size as UInt64.

Floating-Point Numbers

  • Double represents a 64-bit floating-point number.
  • Float represents a 32-bit floating-point number.

Type Safety and Type Inference

swift는 Type Safe 언어이다. 즉 Int로 정해진 변수에 Double타입의 데이터를 대입할수 없다. 그렇다고 모든 상수,변수의 data type을 정해줘야하는 것은 아니다. 처음 대입하는 데이터를 가지고 swift는 알맞은 data type을 정한다. 이를 type inference라고 한다.

Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers.

Numeric Literals

let decimalInteger = 17
let binaryInteger = 0b10001       // 17 in binary notation
let octalInteger = 0o21           // 17 in octal notation
let hexadecimalInteger = 0x11     // 17 in hexadecimal notation

  • 1.25e2 means 1.25 x 102, or 125.0.
  • 1.25e-2 means 1.25 x 10-2, or 0.0125.

let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

Numeric Type Conversion

let cannotBeNegative: UInt8 = -1
// UInt8 cannot store negative numbers, and so this will report an error

let tooBig: Int8 = Int8.max + 1
// Int8 cannot store a number larger than its maximum value,
// and so this will also report an error

let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double

NOTE

The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals don’t have an explicit type in and of themselves. Their type is inferred only at the point that they’re evaluated by the compiler. 그냥 literal 끼리 변수,상수에 할당하기 전에 연산하는 것은 가능하다는 이야기 이다. 

Type Aliases

typealias AudioSample = UInt16

Once you define a type alias, you can use the alias anywhere you might use the original name:

var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0

Booleans

let orangesAreOrange = true
let turnipsAreDelicious = false

let i = 1
if i {
  // this example will not compile, and will report an error, 일반 다른타입의 데이터는 Bool

}

Tuples

The values within a tuple can be of any type and don’t have to be of the same type as each other.

let http404Error = (404, “Not Found”)
let (statusCode, statusMessage) = http404Error

print(“The status code is (statusCode)”)
// Prints “The status code is 404”

print(“The status message is (statusMessage)”)
// Prints “The status message is Not Found”

If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple:

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:

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”

Optionals

You use optionals in situations where a value may be absent.

let possibleNumber = “123”
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type “Int?”, or “optional Int”

위에서 possibleNumber가 다른 일반 string의 경우에는 Int전환이 불가능하다. 그런 경우는 convertedNumber 에 nil 이 저장될수 있으므로 convertedNumber 는 Int?로 자동 설정되는 것이다.

var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404

serverResponseCode = nil
// serverResponseCode now contains no value

NOTE

You can’t use nil with nonoptional constants and variables. If a constant or variable in your code needs to work with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type.

If you define an optional variable without providing a default value, the variable is automatically set to nil for you:

var surveyAnswer: String?
// surveyAnswer is automatically set to nil

If Statements and Forced Unwrapping

You can use an if statement to find out whether an optional contains a value by comparing the optional against nil. You perform this comparison with the “equal to” operator (==) or the “not equal to” operator (!=).

Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. 

if convertedNumber != nil {
   print(“convertedNumber has an integer value of (convertedNumber!).”)
}
// Prints “convertedNumber has an integer value of 123.”

NOTE

Trying to use ! to access a nonexistent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.

Optional Binding

You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable.

if let actualNumber = Int(possibleNumber) {
   print(“”(possibleNumber)” has an integer value of (actualNumber)”)
} else {
   print(“”(possibleNumber)” could not be converted to an integer”)
}
// Prints “"123” has an integer value of 123"

You can include as many optional bindings and Boolean conditions in a single if statement as you need to, separated by commas. If any of the values in the optional bindings are nil or any Boolean condition evaluates to false, the whole if statement’s condition is considered to be false. (여러개의 optional binding을 하나의 if 구문에서 사용하는 것은 여러개의 조건문이 and로 연결된것으로 본다)

if let firstNumber = Int(“4”), let secondNumber = Int(“42”), firstNumber < secondNumber && secondNumber < 100 {
   print(“(firstNumber) < (secondNumber) < 100”)
}
// Prints “4 < 42 < 100”

implicitly Unwrapped Optionals

it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed.

You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type.

let possibleString: String? = “An optional string.”
let forcedString: String = possibleString! // requires an exclamation mark

let assumedString: String! = “An implicitly unwrapped optional string.”
let implicitString: String = assumedString // no need for an exclamation mark

You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value:

if assumedString != nil {
   print(assumedString)
}
// Prints “An implicitly unwrapped optional string.”

You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement:

if let definiteString = assumedString {
   print(definiteString)
}
// Prints “An implicitly unwrapped optional string.”

NOTE

Don’t use an implicitly unwrapped optional when there’s a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable.

Error Handling

When a function encounters an error condition, it throws an error. That function’s caller can then catch the error and respond appropriately.

func canThrowAnError() throws {
   // this function may or may not throw an error
}

A function indicates that it can throw an error by including the throws keyword in its declaration. When you call a function that can throw an error, you prepend the try keyword to the expression.

Swift automatically propagates errors out of their current scope until they’re handled by a catch clause.

do {
   try canThrowAnError()
   // no error was thrown
} catch {
   // an error was thrown
}

A do statement creates a new containing scope, which allows errors to be propagated to one or more catchclauses.

Here’s an example of how error handling can be used to respond to different error conditions:

func makeASandwich() throws {
   // …
}

do {
   try makeASandwich()
   eatASandwich()
} catch SandwichError.outOfCleanDishes {
   washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
   buyGroceries(ingredients)

}

Assertions and Preconditions

You use them to make sure an essential condition is satisfied before executing any further code. If the Boolean condition in the assertion or precondition evaluates to true, code execution continues as usual. If the condition evaluates to false, the current state of the program is invalid; code execution ends, and your app is terminated.

error handling과는 달리 assertions and preconditions aren’t used for recoverable or expected errors. (통과하지 못하면 프로그램 정지)

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.

Debugging with Assertions

let age = -3
assert(age >= 0, “A person’s age can’t be less than zero.”)
// This assertion fails because -3 is not >= 0.

You can omit the assertion message

assert(age >= 0)

If the code already checks the condition, you use the assertionFailure(_:file:line:) 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.”)
}

Enforcing Preconditions

// In the implementation of a subscript…
precondition(index > 0, “Index must be greater than zero.”)

Multiple APK Support | Android Developers