忍者刘米米

2.The Basics

Swift is a type-safe language

which means the language helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. Likewise, type safety prevents you from accidentally passing an optional String to a piece of code that expects a nonoptional String. Type safety helps you catch and fix errors as early as possible in the development process.

Constants and Variables

declare constants with the let keyword and variables with the var keyword

1
2
3
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
var x = 0.0, y = 0.0, z = 0.0

Type Annotations

1
2
var welcomeMessage: String
var red, green, blue: Double

Naming Constants and Variables

1
2
3
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"

Integers

  • Integers are either signed (positive, zero, or negative) or unsigned (positive or zero).
  • Unless you need to work with a specific size of integer, always useInt for integer values in your code
  • Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size:

Floating-Point Numbers

Swift provides two signed floating-point number types:

  • Double represents a 64-bit floating-point number. Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. In situations where either type would be appropriate, Double is preferred
  • Float represents a 32-bit floating-point number.

Numeric Literals

All of these integer literals have a decimal value of 17:

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

All of these floating-point literals have a decimal value of 12.1875:

1
2
3
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

Both integers and floats can be padded with extra zeros and can contain underscores to help with readability

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

Numeric Type Conversion

Integer Conversion

An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255.

1
2
3
4
5
6
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

SomeType(ofInitialValue) is the default way to call the initializer of a Swift type and pass in an initial value

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

Integer and Floating-Point Conversion

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 do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler.

1
2
3
4
5
6
7
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double

let integerPi = Int(pi)
// integerPi equals 3, and is inferred to be of type Int.This means that 4.75 becomes 4, and -3.9 becomes -3.

Type Aliases

Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword.

1
2
3
4
5
typealias AudioSample = UInt16

var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0
// the call to AudioSample.min actually calls UInt16.min

Booleans

Swift provides two Boolean constant values, true and false:

1
2
let orangesAreOrange = true
let turnipsAreDelicious = false

Tuples

What is tuples

Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other.

When to use tuples

  1. Tuples are particularly useful as the return values of functions
  2. Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple.

Declare tuples

“a tuple of type (Int, String)”.

1
2
let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")

Decompose a tuple

You can decompose a tuple’s contents into separate constants or variables

1
2
3
4
5
6
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"

ignore parts of the tuple with an underscore (_) when you decompose the tuple

1
2
3
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"

Access a tuple

access the individual element values in a tuple using index numbers starting at zero:

1
2
3
4
5
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"

name the individual elements in a tuple when the tuple is defined

1
2
3
4
5
6
7
let http200Status = (statusCode: 200, description: "OK")

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

What is optionals

An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all.

nil cannot be used with nonoptional constants and variables.

Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a nonexistent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type.

Optionals of any type can be set to nil, not just object types.

1
2
3
4
5
6
7
8
9
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"

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

serverResponseCode = nil
// serverResponseCode now contains no value

Default value for optionals

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

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

If Statements and Forced Unwrapping

comparison with the “equal to” operator (==) or the “not equal to” operator (!=).

1
2
3
4
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// Prints "convertedNumber contains some integer value."

The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value:

Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.

1
2
3
4
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// Prints "convertedNumber has an integer value of 123."

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.

1
2
3
if let constantName = someOptional {
statements
}

“If the optional Int returned by Int(possibleNumber) contains a value, set a new constant called actualNumber to the value contained in the optional.”

1
2
3
4
5
6
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
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"

Implicitly Unwrapped Optionals

You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it.

Do not use an implicitly unwrapped optional when there is 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.

1
2
3
4
5
6
7
8
9
10
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

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

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

1
2
3
4
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:

1
2
3
4
if let definiteString = assumedString {
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."

Error Handling

1
2
3
4
5
6
7
8
9
10
11
12
func makeASandwich() throws {
// ...
}

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

Assertions

You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated.

1
2
3
4
5
6
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// this causes the assertion to trigger, because age is not >= 0

// assertion message can be omitted if desired
assert(age >= 0)