Docs.swift.org/swift-book/…

For administration, start the first project in a new language by printing “Hello, world!” on the screen. . With Swift, one line of code does the trick.

print(“Hello, world!” )

If you’ve ever written code in C or Objective-C, this syntax will be familiar in Swift, and this line of code is a complete project. Don’t import a separate library that you want to handle input/output or strings for functionality. Code written globally is used as the entry point for the project, so the main () function is not needed. You don’t need a semicolon (;) after each statement .

This example shows you how to start coding with Swift by showing you how to complete a variety of programming tasks. Don’t worry if you don’t understand anything, everything described in the rest of the example is explained in great detail later on.

For a better experience, this section opens a playground with Xcode. Playground allows you to edit code lists and see the results immediately

The value of the simple

Let constructs constants and var constructs variables. Constant values do not need to be known at compile time, but a value must be explicitly assigned. That is, you can use constants to mark values that are determined once and used in many places.

var myVariable = 42

myVariable = 50

let myConstant = 42

A constant or variable must be of the same type as the value to be assigned. However, you don’t need to specify the type every time. When creating a constant or variable, provide a value so that the compiler can deduce its type. In the example above, the compiler deduces that myVariable is an integer because its initialization value is an integer (42).

If the initial value does not provide enough information (or there is no initial value), you need to write the type after the variable and separate it with a semicolon.

let implicitInteger = 70

Let implicitDouble = 70.0

let explicitDouble: Double = 70

Create a constant explicitly using the Float type and the value 4.

A value does not implicitly convert to another type. If you need to convert to another type, explicitly create an instance of the desired type.

let label = “The width is “

let width = 94

let widthLabel = label + String(width)

If I delete the last line and change it to string, what’s wrong?

There is an easier way to introduce values into a string: write values in parentheses preceded by a backslash (\). For example,

let apples = 3

let oranges = 5

let appleSummary = “I have \(apples) apples.”

let fruitSummary = “I have \(apples + oranges) pieces of fruit.”

Use \ () to introduce a floating point value in the string and a person’s name in the greeting

Strings that take more than one line use triple double quotes (“””). As long as the indentation of the closing quotation marks is matched, the indentation at the beginning of each line is removed. Such as:

let quotation = “””

I said “I have \(apples) apples.”

And then I said “I have \(apples + oranges) pieces of fruit.”

“” “

Use square brackets to create arrays and dictionaries that access elements by writing subscripts or key values inside square brackets. The last element can be followed by a comma.

var shoppingList = [“catfish”, “water”, “tulips”]

shoppingList[1] = “bottle of water”

var occupations = [ “Malcolm”: “Captain”, “Kaylee”: “Mechanic”,]

occupations[“Jayne”] = “Public Relations”

The array grows automatically as you add elements.

shoppingList.append(“blue paint”)

print(shoppingList)

Create an empty array or dictionary, using initialization syntax

let emptyArray = [String]()

let emptyDictionary = [String: Float]()

If type information can be derived, write an empty array and an empty dictionary, for example, when passing a new value to a variable or an argument to a function.

shoppingList = []

occupations = [:]

The control flow

Use if and switch for conditional judgment, use for-in, while and repeat-while for loop. Parentheses for conditions and loop variables are optional. Body braces must not be omitted.

let individualScores = [75, 43, 103, 87, 12]

var teamScore = 0

for score in individualScores {

if score > 50{

teamScore += 3

} else {

teamScore += 1

}

}

print(teamScore)

In an if statement, the condition must be a Boolean expression, which means code like if score {… } is an error and cannot be used to implicitly determine whether it is zero.

You can have values that might be nil used together with if and let. These values are represented as optional types. Values of optional types contain a value or nil to indicate that the value is missing. Add? To the value type. Indicates that the value is an optional type.

var optionalString: String? = “Hello”

print(optionalString == nil)

// Prints “false”

var optionalName: String? = “John Appleseed”

var greeting = “Hello!”

if let name = optionalName {

greeting = “Hello, \(name)”

}

Change optionalName to nil. What greeting will you get? Add an else clause and set the greeting to another value when optionalName is nil

If the optional value is nil, the condition becomes false and the code in the braces skips. Otherwise, the optional value is unpacked and assigned to the constant after the let, so that the code in the block can obtain the unpacked value.

You can also use?? The operator provides default values for handling optional types. If the optional value is missing, the default value is used instead.

let nickName: String? = nil

let fullName: String = “John Appleseed”

let informalGreeting = “Hi \(nickName ?? fullName)”

Switches support arbitrary types of data and a wealth of comparators – unrestricted integer and equality tests

let vegetable = “red pepper”

switch vegetable {

case “celery”:

print(“Add some raisins and make ants on a log.”)

case “cucumber”, “watercress”:

print(“That would make a good tea sandwich.”)

case let x where x.hasSuffix(“pepper”):

print(“Is it a spicy \(x)?” )

default:

print(“Everything tastes good in soup.”)

}

// Prints “Is it a spicy red pepper?”

Try removing the default case and see what goes wrong

Notice how the let in the template assigns values to constants in the matching template.

After executing the code in the matching switch case, the program exits from the switch statement. Execution does not continue to the next case, so there is no need to explicitly exit switch at the end of every case code in Seitch.

Use key-value pairs to traverse the dictionary for in by providing pairs of names. Dictionaries are unordered collections, and their keys and values are traversed in disorder.

let interestingNumbers = [

“Prime”: [2, 3, 5, 7, 11, 13],

“Fibonacci”: [1, 1, 2, 3, 5, 8],

“Square”: [1, 4, 9, 16, 25],

]

var largest = 0

for (kind, numbers) in interestingNumbers {

for number in numbers {

if number > largest {

largest = number

}

}

}

print(largest)// Prints “25”

Add another variable to record which type of plague is the largest, same as which plague is the largest.

Use while to repeat a block until the state changes. The state of the loop can be at the tail, ensuring that the loop executes at least once.

var n = 2

while n < 100 {

n *= 2

}

print(n)// Prints “128”

var m = 2

repeat {

m *= 2

} while m < 100

print(m)// Prints “128”

Can be done by using.. < keeps index values in a loop to generate indexes in a range.

var total = 0

for i in 0.. {< 4

total += i

}

print(total)// Prints “6”

Use.. < get an ignore maximum value range, using… Gets a value range that includes both ends

Functions and closures

Declare a function using func. The function is called by following the function name with a list of arguments in parentheses. Use -> to separate the type of the parameter name from the function return type.

func greet(person: String, day: String) -> String {

return “Hello \(person), today is \(day).”

}

greet(person: “Bob”, day: “Tuesday”)

Remove the day parameter. Add a parameter to include lunch today in the greeting.

By default, functions use parameter names as argument names. Write a custom argument tag before the parameter, or use _ instead of the argument tag.

func greet(_ person: String, on day: String) -> String {

return “Hello \(person), today is \(day).”

}

greet(“John”, on: “Wednesday”)

Use a meta-ancestor to create a composite value – for example, returning multiple values from a function. Primitive elements can be referenced by name or number.

func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {

var min = scores[0]

var max = scores[0]

var sum = 0

for score in scores {

if score > max {

max = score

} else if score < min {

min = score

}

sum += score

}

return (min, max, sum)

}

let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])

print(statistics.sum)// Prints “120”print(statistics.2)// Prints “120”

Functions can be nested. Nested functions can call variables declared outside the function. You can use nested functions to organize the code for long or complex functions.

func returnFifteen() -> Int {

var y = 10

func add() {

y += 5

}

add()

return y

}

returnFifteen()

The function is of first-class type. So a function can return another function as a return value.

func makeIncrementer() -> ((Int) -> Int) {

func addOne(number: Int) -> Int {

return 1 + number

} return

addOne

}

var increment = makeIncrementer()

increment(7)

One argument to a function can be another function.

func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {

for item in list {

if condition(item) {

return true

}

} return false

}

func lessThanTen(number: Int) -> Bool {

return number < 10

}

var numbers = [20, 19, 7, 12]

hasAnyMatches(list: numbers, condition: lessThanTen)

A function is really a special kind of closure: a block of code that can be called later. Variables that are available where closures are created can be used in parallel with functions, even when closures are executed in a different location – inline functions have seen examples of this. You can define a closure that has no name around the code in braces. Use in to separate the real participation return value types.

numbers.map({ (number: Int) -> Int in

let result = 3 * number return result

})

Parameters can be referenced by numbers instead of names. This approach is useful in very short closures. Closures can appear as the last argument to a function, followed by parentheses. When the closure is the only argument to the function, you can omit the parentheses entirely.

let sortedNumbers = numbers.sorted {
0 > 0 >
1 }

print(sortedNumbers)// Prints “[20, 19, 12, 7]”

Object and class

Class creates a class followed by the class name. Attributes are declared in the same way as constants or variables, except that they are declared in the context of the class. Similarly, method and function declarations are used in the same way.

class Shape {

var numberOfSides = 0

func simpleDescription() -> String {

return “A shape with \(numberOfSides) sides.”

}

}

Use let to add a constant property, and add a method that takes one parameter.

Create a city by using parentheses after the class name. Get the properties and methods of a class using dot syntax.

var shape = Shape()

shape.numberOfSides = 7

var shapeDescription = shape.simpleDescription()

This version of shape is missing something important: it uses the initialization constructor to configure a class when it is created. Create one using init.

class NamedShape {

var numberOfSides: Int = 0

var name: String

init(name: String) {

self.name = name

}

func simpleDescription() -> String {

return “A shape with \(numberOfSides) sides.”

}

}

Notice how self is used during initialization to distinguish the name attribute from the name parameter. The arguments passed to the initializer when creating an instance of the class are the same as those passed to the function when calling it. Each attribute needs to be assigned a value — either when declared or when initialized.

You can use deinit to create a resolver if you need to do some cleaning before the object is decomposed.

Subclasses contain the name of their parent class after their class name, separated by a semicolon. Classes are not required to inherit from a standard root class, so parent classes can be included or omitted as required.

Methods in subclasses that override the parent implementation are marked with Override — occasionally overriding a method will be detected by the compiler as an error if override is not written. The compiler also checks for methods that use Override but don’t actually override any of the parent methods.

class Square: NamedShape {

var sideLength: Double

init(sideLength: Double, name: String) {

self.sideLength = sideLength

super.init(name: name)

numberOfSides = 4

}

func area() -> Double {

return sideLength * sideLength

}

override func simpleDescription() -> String {

return “A square with sides of length \(sideLength).”

}

}

Let test = Square(sideLength: 5.2, name: “my test Square “)

test.area()

test.simpleDescription()

Generates another subclass of NamedShape, Circle. The initialization method takes a radius and a name as arguments. Implement area () and simpleDescription () methods in the circle class

In addition to simply storing properties, properties can have getter and setter methods.

class EquilateralTriangle: NamedShape {

Var sideLength: Double = 0.0

init(sideLength: Double, name: String) {

self.sideLength = sideLength

super.init(name: name) numberOfSides = 3

}

var perimeter: Double {

get {

The return of 3.0 * sideLength

} set {

SideLength = newValue / 3.0

}

}

override func simpleDescription() -> String {

return “An equilateral triangle with sides of length \(sideLength).”

}

}

Var triangle = EquilateralTriangle(sideLength: 3.1, name: “triangle”)print(triangle. Perimeter)// Prints “9.3”

Triangle. Generating = 9.9

Print (triangle. SideLength) / / Prints “3.3000000000000003”

In the setters of perimeter, the newvalue potential name is newvalue. You can provide an explicit name in parentheses after set.

Note that the EquilateralTriangle initialization has three steps:

1. Set values for properties declared by subclasses

2. Call the initialization method of the parent class

3. Change the value of the real name attribute of the parent class. Other calling methods, getters, or setters Settings are also performed here.

Use willSet and didSet if you don’t need to evaluate properties but need to run a code before and after setting new values. This code is executed when the value changes outside of the initialization method. For example, the following class ensures that the sides of a triangle are known to be equal to the sides of a square.

class TriangleAndSquare {

var triangle: EquilateralTriangle {

willSet {

square.sideLength = newValue.sideLength

}

}

var square: Square {

willSet {

triangle.sideLength = newValue.sideLength

}

}

init(size: Double, name: String) {

square = Square(sideLength: size, name: name)

triangle = EquilateralTriangle(sideLength: size, name: name)

}

}

var triangleAndSquare = TriangleAndSquare(size: 10, name: “another test shape”)print(triangleAndSquare.square.sideLength)// Prints “10.0” print (triangleAndSquare. Triangle. SideLength) / / Prints “10.0” triangleAndSquare. Square = square (sideLength: 50, name: “larger square”) print (triangleAndSquare. Triangle. SideLength) / / Prints “50.0”

When using values of optional types, use? Before operations on methods, attributes, and subscripts. . If? The last value is nil, right? And then everything is ignored, and the value of the whole expression is nil. Otherwise, optional type unpack,? Then everything operates on the unpacked value. In both cases, the entire expression is an optional type.

Enumerations and structures

Create an enumeration using enum. Like classes and other named types, enumerations can set the methods associated with them.

enum Rank:Int {

case ace = 1

case two, three, four, five, six, seven, eight, nine, ten

case jack, queen, king

func simpleDescription() -> String {

switch self {

case .ace:

return “ace”

case .jack:

return “jack”

case .queen:

return “queen”

case .king:

return “king”

default:

return String(self.rawValue)

}

}

}

let ace = Rank.ace

let aceRawValue = ace.rawValue

Write a function to compare the raw values of rank

Use the init? The (rawValue:) initializer generates an instance of an enumeration of raw values. Returns an enumeration case that matches the raw value or nil if no rank is matched.

if let convertedRank = Rank(rawValue: 3) {

let threeDescription = convertedRank.simpleDescription()

}

Enumerated case values are real values, not just another way of using raw values. In fact, cases that have no actual value need not be given a value.

enum Suit {

case spades, hearts, diamonds, clubs

func simpleDescription() -> String {

switch self {

case .spades:

return “spades”

case .hearts:

return “hearts”

case .diamonds:

return “diamonds”

case .clubs:

return “clubs”

}

}

}

let hearts = Suit.hearts

let heartsDescription = hearts.simpleDescription()

Add a color () method to suit, return “black” to spades and clubs, and “red” to hearts and diamonds.

Note the two references to hearts enumerated above: When assigning a value to the hearts constant, the enumeration case uses the suet.hearts full name reference because the constant does not specify a type explicitly. In switch, the enumeration case references.hearts because the value of self is already used as the outer layer. The short form can be used whenever the value type is already known.

If the enumeration has RAW values, those values are determined at declaration time, meaning that each particular instance usually has the same RAW value. Another option for cases of enumerations is to have values associated with cases — values that are determined when the instance is retrieved, and each instance of the same enumeration case can be different. You can think of the associated value of an enumerated case as a storage property. The server can respond with the request information or with a detailed description of the error.

enum ServerResponse {

case result(String, String)

case failure(String)

}

let success = ServerResponse.result(“6:00 am”, “8:09 pm”)

let failure = ServerResponse.failure(“Out of cheese.”)

switch success {

case let .result(sunrise, sunset):

print(“Sunrise is at \(sunrise) and sunset is at \(sunset).”)

case let .failure(message):

print(“Failure… \(message)”)

}

// Prints “Sunrise is at 6:00 am and sunset is at 8:09 pm.”

Add a third Case ServerResponse and add it to the Switch

Notice in Switch Cases how the Sunrise and Sunset times are extracted as partial match values from ServerResponse.

Create a structure using struct. Structs support many of the same capabilities as classes, including methods and initializer constructors. One of the biggest differences between structures and classes is that structures are usually copied as they pass through code, whereas classes pass references.

struct Card {

var rank: Rank

var suit: Suit

func simpleDescription() -> String {

return “The \(rank.simpleDescription()) of \(suit.simpleDescription())”

}

}

let threeOfSpades = Card(rank: .three, suit: .spades)

let threeOfSpadesDescription = threeOfSpades.simpleDescription()

Write a function that returns an array of cards, each rank and suit combined into a card.

Protocols and Extensions

Uses protocol to declare a protocol.

protocol ExampleProtocol {

var simpleDescription: String { get}

mutating func adjust()

}

Classes, enumerations, and structures can all adopt protocols.

class SimpleClass: ExampleProtocol {

var simpleDescription: String = “A very simple class.”

var anotherProperty: Int = 69105

func adjust() {

simpleDescription += ” Now 100% adjusted.”

}

}

var a = SimpleClass()

a.adjust()

let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {

var simpleDescription: String = “A simple structure” mutating

func adjust() {

simpleDescription += ” (adjusted)”

}

}

var b = SimpleStructure()

b.adjust()

let bDescription = b.simpleDescription

Add another method to ExampleProtocol that must be implemented. What adjustments do you have to make to SimpleClass and SimpleStructure that they still adhere to the protocol?

Notice the use of the mutating keyword in SimpleStructure life to mark methods that can modify the structure. The SimpleClass class declaration does not require a mutating tag because the methods of a class usually change the class.

Use Extension to add functionality to an existing type, such as a new method or evaluated property. Extensions can be used to add compliance to classes declared anywhere, even from libraries or packages.

extension Int: ExampleProtocol {

var simpleDescription: String {

return “The number \(self)”

}

mutating func adjust() {

self += 42

}

}

print(7.simpleDescription) // Prints “The number 7”

Write an extension to double that adds the absoluteValue property

You can use a protocol name just like any other named type — for example, to create a collection of different types that all conform to a protocol object. When you use a value of a type that complies with a protocol, methods defined outside the protocol are not available.

let protocolValue: ExampleProtocol = a

print(protocolValue.simpleDescription)

// Prints “A very simple class. Now 100% adjusted.”

// print(protocolValue.anotherProperty) // Uncomment to see the error

Even if the protocolValue runtime is of type SimpleClass, the compiler treats it as if the given type is ExampleProtocol. Means that methods and properties implemented outside of the protocol cannot be manipulated.

Error handling

Any class that follows the error protocol can be used to represent errors.

enum PrinterError: Error {

case outOfPaper

case noToner

case onFire

}

Throw is used to throw an error, and throws marks functions that might throw an error. If an error occurs in a function, the function returns immediately, and the calling code handles the error.

func send(job: Int, toPrinter printerName: String) throws -> String {

if printerName == “Never Has Toner” {

throw PrinterError.noToner

}

return “Job sent”

}

There are several ways to handle errors. One is to use a do catch. In the DO block, place a try before any code that might throw an error. In a catch block, unless you customize the name, the error is automatically assigned the name error.

do {

let printerResponse = try send(job: 1040, toPrinter: “Bi Sheng”)

print(printerResponse)

} catch {

print(error)

} // Prints “Job sent”

Change the name of printer to “Never Has Toner”, send(Job :toPrinter:) throws an error.

You can provide multiple catch speeds to handle specific errors. You can write templates after a catch like a case in switch.

do {

let printerResponse = try send(job: 1440, toPrinter: “Gutenberg”)

print(printerResponse)

} catch PrinterError.onFire {

print(“I’ll just put this over here, with the rest of the fire.”)

} catch let printerError as PrinterError {

print(“Printer error: \(printerError).”)

} catch {

print(error)

} // Prints “Job sent”

Add an error throwing code to a do block. What type of error do you need to throw to be handled by the first catch block? What about the second and third blocks?

Another way to handle errors is try? Convert the result to an optional type. If the function runs an error, the special error is discarded and the result becomes nil. Otherwise, the result is an optional type containing function returns.

let printerSuccess = try? send(job: 1884, toPrinter: “Mergenthaler”)

let printerFailure = try? send(job: 1885, toPrinter: “Never Has Toner”)

Use defer to write a block of code that executes after all the other code in the function has been executed and before the function returns. The code executes whether or not the function throws an error. You can use defer to write setup and cleanup code, even if it needs to be executed at different times.

var fridgeIsOpen = false

let fridgeContent = [“milk”, “eggs”, “leftovers”]

func fridgeContains(_ food: String) -> Bool {

fridgeIsOpen = true

defer {

fridgeIsOpen = false

}

let result = fridgeContent.contains(food)

return result

}

fridgeContains(“banana”)

print(fridgeIsOpen) // Prints “false”

The generic

Write a name in an extension sign to indicate the generics of a function or class.

func makeArray(repeating item: Item, numberOfTimes: Int) -> [Item] {

var result = [Item]()

for _ in 0.. <numberOfTimes {

result.append(item)

}

return result

}

makeArray(repeating: “knock”, numberOfTimes: 4)

You can use generics to form functions and methods, just like classes, enumerations, and structs.

// Reimplement the Swift standard library’s optional type enum OptionalValue {

case none

case some(Wrapped)

}

var possibleInteger: OptionalValue = .none

possibleInteger = .some(100)

Use WHERE before the body to specify some necessary conditions — for example, you need the class to implement a protocol, you need two classes to be the same, or you need the class to have a special parent.

func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool where T.Element: Equatable, T.Element == U.Element {

for lhsItem in lhs {

for rhsItem in rhs {

if lhsItem == rhsItem {

return true

}

}

}

return false

}

anyCommonElements([1, 2, 3], [3])

Modify anyCommonElements(_:_:) to get a function that returns an array containing elements from both sequences.