Swift closure / enumeration

1. Swift closure

Closures are self-contained functional code blocks that can be used in code or passed as parameters.

Closures in Swift are similar to code blocks in C and Objective-C and anonymous functions in some other programming languages.

Global functions and nested functions are actually special closures.

The forms of closures are:

Global functionNested functionClosure expression
Has a name but cannot capture any values.If you have a name, you can also capture the value in a closed function.Anonymous closures, using lightweight syntax, can capture values according to the context.

Closures in Swift have many optimizations:

  1. Infer parameter and return value types from context
  2. Implicitly return from a single line expression closure (that is, the closure body has only one line of code, and return can be omitted)
  3. You can use simplified parameter names, such as $0, $1 (starting from 0, indicating the ith parameter...)
  4. Trailing closure syntax is provided

Syntax:

The following defines a receive parameter and returns the closure syntax of the specified type:

{(parameters) -> return type in
   statements
}

example:

import Cocoa

let studname = { print("Swift Closure instance.") }
studname()

The output result of the above program execution is:

Swift Closure instance.

The following closure takes two parameters and returns a Boolean value:

{(Int, Int) -> Bool in
   Statement1
   Statement 2
    ---
   Statement n
}

example:

import Cocoa

let divide = {(val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}
let result = divide(200, 20)
print (result)

The output result of the above program execution is:

10

1.1 closure expression

Closure expressions are a way to construct inline closures using concise syntax. Closure expressions provide some syntax optimizations to make writing closures simple and straightforward.
sorted method
The Swift standard library provides a method called sorted(by:), which sorts the values in the array of known types according to the closure function you provide for sorting.
After sorting, the sorted(by:) method will return a new array with the same size as the original array, containing elements of the same type, and the elements have been sorted correctly. The original array will not be modified by the sorted(by:) method.
The sorted(by:) method needs to pass in two parameters:

  1. Arrays of known types
  2. Closure function, which needs to pass in two values of the same type as the array element and return a Boolean value to indicate whether the first parameter passed in is before or after the second parameter after sorting. If the first parameter value appears in front of the second parameter value, the sort closure function needs to return true, otherwise it returns false.

example:

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

// Ordinary functions (or embedded functions) are used to provide sorting functions. The type of closure function needs to be (string, string) - > bool.
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)

print(reversed)

The output result of the above program execution is:

["S", "D", "BE", "AT", "AE"]

If the first string s1 is greater than the second string (s2), the backwards function returns true, indicating that s1 should appear before s2 in the new array. For characters in A string, "greater than" means "later in alphabetical order". This means that the letter "B" is greater than the letter "A" and the string "s" is greater than the string "D". It will be sorted alphabetically in reverse order, and "AT" will be listed before "AE".

1.2 parameter name abbreviation

Swift automatically provides parameter name abbreviations for inline functions. You can call the parameters of closures in sequence through $0, $1, $2.

example:

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

var reversed = names.sorted( by: { $0 > $1 } )
print(reversed)

$0 and $1 represent the first and second String type parameters in the closure.

The output result of the above program execution is:

["S", "D", "BE", "AT", "AE"]

If you use parameter name abbreviations in the closure expression, you can omit the definition in the closure parameter list, and the type of the corresponding parameter name abbreviations will be inferred from the function type. The in keyword can also be omitted.

1.3 operator function

In fact, there is a shorter way to write the closure expression in the above example.

Swift's String type defines the String implementation of the greater than sign (>), which accepts two String type parameters as a function and returns the value of Bool type. This exactly matches the function type required by the second parameter of the sort(:) method. Therefore, you can simply pass a greater than sign, and swift can automatically infer that you want to use the String function with a greater than sign:

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

var reversed = names.sorted(by: >)
print(reversed)

The output result of the above program execution is:

["S", "D", "BE", "AT", "AE"]

1.4 trailing closure

A trailing closure is a closure expression written after the parentheses of a function, and the function supports calling it as the last parameter.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // Function body part
}

// The following is a function call without a trailing closure
someFunctionThatTakesAClosure({
    // Closure body
})

// The following is a function call using a trailing closure
someFunctionThatTakesAClosure() {
  // Closure body
}

example:

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

//Trailing closure
var reversed = names.sorted() { $0 > $1 }
print(reversed)

The {$0 > $1} after sort() is a trailing closure.
The output result of the above program execution is:

["S", "D", "BE", "AT", "AE"]

Note: if the function requires only one argument to the closure expression, you can even omit () when you use trailing closures.
reversed = names.sorted { $0 > $1 }

1.5 capture value

Closures can capture constants or variables in the context of their definition.
Even if the original field that defines these constants and variables no longer exists, the closure can still reference and modify these values in the closure function body.
Swift's simplest form of closure is nested functions, that is, functions defined in the function bodies of other functions.
Nested functions can capture all parameters of their external functions and defined constants and variables.

Look at this example:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

A function makeIncrementor has an Int type parameter amout, and it has an external parameter name forincrement, which means that you must use this external name when calling. The return value is a function of () - > Int.
In the function body, the variable runningTotal and a function increment are declared.
The incrementor function does not take any parameters, but the runningTotal and amount variables are accessed in the function body. This is because it is implemented by capturing runningTotal and amount variables that already exist in the body of the function containing it.
Since the amount variable is not modified, incrementor actually captures and stores a copy of the variable, which is stored with incrementor.

So when we call this function, we will accumulate:

import Cocoa

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)

// The returned value is 10
print(incrementByTen())

// The returned value is 20
print(incrementByTen())

// The returned value is 30
print(incrementByTen())

The output result of the above program execution is:

10
20
30

1.6 closures are reference types

In the above example, incrementByTen is a constant, but the closure pointed to by these constants can still increase the value of its captured variable.
This is because both functions and closures are reference types.
Whether you assign a function / closure to a constant or variable, you actually set the value of the constant / variable to the reference of the corresponding function / closure. In the above example, the reference of incrementByTen to the closure is a constant, not the closure content itself.

This also means that if you assign a closure to two different constants / variables, both values point to the same closure:

import Cocoa

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)

// The returned value is 10
incrementByTen()

// The returned value is 20
incrementByTen()

// The returned value is 30
incrementByTen()

// The value returned is 40
incrementByTen()

let alsoIncrementByTen = incrementByTen

// The value returned is also 50
print(alsoIncrementByTen())

The output result of the above program execution is:

50

Learning address: rookie tutorial( https://www.runoob.com/swift/swift-closures.html)

2. Swift enumeration

Enumeration is simply a data type, but this data type only contains customized specific data. It is a collection of data with common characteristics.
The enumeration of Swift is similar to the structure of Objective C and C. the functions of enumeration are:

  • It is declared in a class, and its value can be accessed by instantiating the class.
  • Enumerations can also define initializers to provide an initial member value; their functionality can be extended from the original implementation.
  • protocols can be followed to provide standard functions.

Syntax:

enum keywords are used in Swift to create enums and their entire definitions are placed in a pair of braces:

enum enumname {
   // The enumeration definition is here
}

For example, we define the following enumeration representing weeks:

import Cocoa

// Define enumeration
enum DaysofaWeek {
    case Sunday
    case Monday
    case TUESDAY
    case WEDNESDAY
    case THURSDAY
    case FRIDAY
    case Saturday
}

var weekDay = DaysofaWeek.THURSDAY
weekDay = .THURSDAY
switch weekDay
{
case .Sunday:
    print("Sunday")
case .Monday:
    print("Monday")
case .TUESDAY:
    print("Tuesday")
case .WEDNESDAY:
    print("Wednesday")
case .THURSDAY:
    print("Thursday")
case .FRIDAY:
    print("Friday")
case .Saturday:
    print("Saturday")
}

The output result of the above program execution is:

Thursday

The values defined in the enumeration (such as Sunday, Monday,..., and Saturday) are the member values (or members) of this enumeration. The case keyword indicates that a new row of member values will be defined.

Note: unlike C and Objective-C, Swift's enumeration members are not given a default integer value when they are created. In the above DaysofaWeek example, Sunday, Monday,... And Saturday are not implicitly assigned to 0, 1,... And 6. On the contrary, these enumeration members themselves have complete values, which are well-defined DaysofaWeek types.

var weekDay = DaysofaWeek.THURSDAY 

The type of weekDay can be inferred when it is initialized by a possible value of DaysofaWeek. Once weekDay is declared as a day of a week, you can use an abbreviation syntax Set it to the value of another DaysofaWeek:

var weekDay = .THURSDAY 

When the type of weekDay is known, assign it again to omit the enumeration name. Using explicitly typed enumeration values can make the code more readable.

Enumeration can be divided into related values and original values.

2.1 difference between relevant value and original value

Correlation valueOriginal value
Different data typesSame data type
Example: enum {10,0.8,"Hello"}Example: enum {10,35,50}
Values are created based on constants or variablesPre populated values
The correlation value is set when you create a new constant or variable based on enumeration members, and its value can be different every time you do so.The original value is always the same

2.2 relevant values

In the following example, we define an enumeration type named Student, which can be a String of Name or a related value of Mark (Int, Int, Int).

import Cocoa

enum Student{
    case Name(String)
    case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
    print("What is the student's name: \(studName). ")
case .Mark(let Mark1, let Mark2, let Mark3):
    print("What is the student's grade: \(Mark1),\(Mark2),\(Mark3). ")
}

The output result of the above program execution is:

What is the student's grade: 98,97,95. 

2.3 original value

The original value can be a string, character, or any integer or floating-point value. Each original value must be unique in its enumeration declaration.
When enumerating with the original value as an integer, you do not need to explicitly assign a value to each member, and Swift will automatically assign a value to you.
For example, when an integer is used as the original value, the implicitly assigned value is incremented by 1. If the first value is not assigned an initial value, it will be automatically set to 0.

import Cocoa

enum Month: Int {
    case January = 1, February, March, April, May, June, July, August, September, October, November, December
}

let yearMonth = Month.May.rawValue
print("The number month is: \(yearMonth). ")

The output result of the above program execution is:

The number month is: 5. 

Learning address: rookie tutorial( https://www.runoob.com/swift/swift-enumerations.html)

Keywords: Swift iOS

Added by inSaneELF on Fri, 17 Dec 2021 15:00:26 +0200