Simple Values
Constant & Variable
- Use
let
to make a constant andvar
to make a variable. - Type can be inferred by compiler.
1 | var myVariable = 42 |
Explicit declare
1 | let explicitDouble: Double = 70 |
Type Conversion
1 | let label = "The width is " |
Placeholder
1 | let apples = 3 |
Array and dictionary
1 | var shoppingList = ["catfish", "water", "tulips", "blue paint"] |
Empty array or dictionary
1 | let emptyArray = [String]() |
Type inferred
1 | shoppingList = [] |
Control Flow
- Use
if
andswitch
to make conditionals - use
for-in
, for,while
, andrepeat-while
to make loops - Parentheses around the condition or loop variable are optional. Braces around the body are required.
For in
1 | let individualScores = [75, 43, 103, 87, 12] |
For in range condition (..<)
Use ..<
to make a range that omits its upper value, and use …
to make a range that includes both values.
1 | var total = 0 |
For-in iterate dictionary
1 | let interestingNumbers = [ |
If - let unwrap optionals
An optional value either contains a value or contains nil to indicate that a value is missing
1 | var optionalString: String? = "Hello" |
Default value for Optional (??)
default value using the ?? operator. If the optional value is missing, the default value is used instead.
1 | let nickName: String? = nil |
Switch
- Switches support any kind of data
- 注意下面的 case 里可以设置let 常量进行计算,这样case 可以满足多多种自定义的条件,而不仅仅是比较相等
1 | let vegetable = "red pepper" |
While
while to repeat a block of code until a condition changes
1 | var n = 2 |
Functions and Closures
1 | func greet(person: String, day: String) -> String { |
Custom argument label
custom argument label before the parameter name, or write _ to use no argument label
1 | func greet(_ person: String, on day: String) -> String { |
Return multiple values by tuple
1 | func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) { |
Take a variable number of arguments
1 | func sumOf(numbers: Int...) -> Int { |
Nested functions
1 | func returnFifteen() -> Int { |
Function as variable
Return another function as its value.
1 | func makeIncrementer() -> ((Int) -> Int) { |
A function can take another function as one of its arguments.
1 | func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool { |
Closure
- write a closure without a name by surrounding code with braces ({}). Use
in
to separate the arguments and return type from the body. - The code in a closure has access to things like variables and functions that were available in the scope where the closure was created, even if the closure is in a different scope when it is executed
1 | var numbers = [20, 19, 7, 12] |
Single statement closures
1 | let mappedNumbers = numbers.map({ number in 3 * number }) |
- You can refer to parameters by number instead of by name.
- A closure passed as the last argument to a function can appear immediately after the parentheses.
- When a closure is the only argument to a function, you can omit the parentheses entirely.
1 | let sortedNumbers = numbers.sorted { $0 > $1 } |
Objects and Classes
1 | class Shape { |
Property value assigned is required
Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).
1 | class NamedShape { |
Subclasses
- There is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.
- Methods on a subclass that override the superclass’s implementation are marked with
override
1 | class Square: NamedShape { |
Getter and setter
Notice the init method
1 | class EquilateralTriangle: NamedShape { |
Computed property
Computed based on the simple property
1 | var perimeter: Double { |
WillSet and didSet
- If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet.
- The code you provide is run any time the value changes outside of an initializer.
1 | // For example, the class below ensures that the side length of its triangle is always the same as the side length of its square |
Optional chain
- If the value before the
?
is nil, everything after the?
is ignored and the value of the whole expression is nil. - Otherwise, the optional value is unwrapped, and everything after the
?
acts on the unwrapped value. - In both cases, the value of the whole expression is an optional value.
1 | let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") |
Enumerations and Structures
Raw value
- By default, Swift assigns the raw values starting at zero and incrementing by one each time
Ace
is explicitly given a raw value of 1, and the rest of the raw values are assigned in order.- Use the rawValue property to access the raw value of an enumeration case.
1 | enum Rank: Int { |
init? (rawValue:)
Use theinit?(rawValue:)
initializer to make an instance of an enumeration from a raw value
1 | if let convertedRank = Rank(rawValue: 3) { |
No raw value
1 | enum Suit { |
Associated values
these values are determined when you make the instance, and they can be different for each instance of an enumeration case
1 | enum ServerResponse { |
Struct
One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.
1 | struct Card { |
Protocols and Extensions
Protocols
Use protocol to declare a protocol.
1 | protocol ExampleProtocol { |
Classes, enumerations, and structs can all adopt protocols.
1 | class SimpleClass: ExampleProtocol { |
Protocol type
- use a protocol name just like any other named type
- When you work with values whose type is a protocol type, methods outside the protocol definition are not available
- Even though the variable
protocolValue
has a runtime type ofSimpleClass
, the compiler treats it as the given type ofExampleProtocol
. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.
1 | let protocolValue: ExampleProtocol = a |
Extensions
Use extension to add functionality to an existing type, such as new methods and computed properties
1 | extension Int: ExampleProtocol { |
Error Handling
represent errors using any type that adopts the Error
protocol.
1 | enum PrinterError: Error { |
Throw & Throws
Use throw
to throw an error and throws
to mark a function that can throw an error. If you throw an error in a function, the function returns immediately and the code that called the function handles the error.
1 | func send(job: Int, toPrinter printerName: String) throws -> String { |
Handle error 1: Do-catch
1 | do { |
Handle error 2: Multiple catch blocks
1 | do { |
Handle errors3: by try?
Another way to handle errors is to use try? to convert the result to an optional. If the function throws an error, the specific error is discarded and the result is nil. Otherwise, the result is an optional containing the value that the function returned.
1 | let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler") |
Defer
Use defer
to write a block of code that is executed after all other code in the function, just before the function returns. The code is executed regardless of whether the function throws an error. You can use defer to write setup and cleanup code next to each other, even though they need to be executed at different times.
1 | var fridgeIsOpen = false |
Generics
Write a name inside angle brackets to make a generic function or type.
1 | func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] { |
You can make generic forms of functions and methods, as well as classes, enumerations, and structures.
1 | // Reimplement the Swift standard library's optional type |
Use where
right before the body to specify a list of requirements
1 | func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool |
Writing <T: Equatable>
is the same as writing <T> ... where T: Equatable>
.