• “This is the first day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021”

preface

Swift is being used by more and more companies, so learning Swift should be on the agenda. This paper will first explore the functions in Swift, mainly including the following aspects:

  • Swift function definition
  • Swift function parameters and return values
  • Swift overloading
  • Convergence function optimization
  • Function types, nested functions

I. Swift function definition

A function definition contains its name, body, parameters, and return value. It defines what the function does, receives, and returns. The function name is preceded by the func keyword. Here is an example of a complete function:

func greet(person: String) -> String {
    let greeting = "Hello, " + person + "!"
    return greeting
}
Copy the code
  • The function name is greet
  • Parameters: The parentheses (person: String) are the parameters, person is the parameter name, and String is the type
  • Return value: Use a -> to specify the return value of the function. In this case, we define a String return value

Function return values and parameters

2.1 Function Return Value

From the point of view of return value, functions can be divided into two types: return value and no return value. A function with no return value can be defined in one of three ways:

func testA(a) -> Void{}func testB(a) -> () {
}

func testC(a){}let a = testA()
let b = testB()
let c = testC()

Copy the code

printA, B, CIt can be found that the types of the three are(a), i.e.,An empty tuple. inVoidYou can also find it in SwiftVoidIt’s an empty tuple.That is to say, the above three methods are equivalent, all representing the case of no return value, but the last method is more convenient from the point of view of code brevity.

There is also a case where a function returns a value, as described in the first section, that is, a function that returns a String. In Swift, the return value of a function can be returned implicitly, and the return keyword can be omitted if there is only one return code in the function body. As shown in the following code, the two are equivalent:

func testD(a) -> String {
    return "Normal return"
}
func testE(a) -> String {
    "Implicit return"
}
Copy the code

Multiple return values can also be implemented in Swift via tuples, as follows:

func compute(a:Int.b: Int) -> (sum: Int, difference: Int) {
    return (a+b, a-b);
}
Copy the code

The function compute returns a tuple of summation and difference, allowing multiple values to be returned.

2.2 Function Parameters

Unlike OC,SwiftThe argument to the function inletParameter values are not modifiable. As shown in the figure below, it can be proved.

2.2.1 Function Labels

SwiftThe function parameter of the. Parameters are used inside functions to make use of the function body unambiguous, while function tags are used during function calls to increase readability. Function tags can be omitted, using_And it’s worth noting that,_This is not the same as not setting the function label, as shown below: When using_When, calling a function does not display the function label, and leaving the function label unset takes the parameter as the function label.

2.2.2 Default Function Parameter Values

SwiftFunction parameters can be set to default values. Parameters with default values can be called without argumentsSince parameter A has a default value of 8, you can just pass parameter B on the call. Similarly, if the parameters have default values, the function can be called without passing any values.As shown in the figure, since both parameters have default values, no value is passed when called, just as if a function with no parameters was called.

SwiftSetting function parameter defaults can be out of order becauseSwiftThere is no ambiguity with function tags in. And in theC++, must be set in the order from right to left. The comparison between the two is as follows: The next picture isC++The default value of b is missing, while the default value of B is missingSwiftMedium does not. However, ifSwiftFunction parameters have hidden function labels, so it cannot be identified which parameter is assigned, so it can only be assigned from right to left, which will generate an error, as shown in the following figure:Error missing the second argument when calling a function. Therefore, in theSwiftIf the function parameter label is omitted, ensure that all function parameters have values or can be assigned.

2.2.3 Variable Parameters

With the OCNSLogSame parameters,SwiftFunctions also provide mutable arguments, which are defined in the following wayParameter name: Type..., you can refer to the systemprintFunction definition: printThe first argument to the function is a mutable argument of typeAny, can accept any type, input with.Divide can.

One thing to note about mutable arguments is that the argument label cannot be omitted immediately after the argument, as shown in the following figure:

The parameter b is also of type Any. If the parameter label is omitted, there is no label distinction when calling the function. By itself, the compiler cannot determine whether to assign the parameter to item or to b, so it will report an error.

A variable argument is essentially an array, and you can use arguments inside a function to view their types as follows:You can seeitemIt’s actually an array of type Any.

2.2.4 Parameters modified by inout

In OC and C, we can change the value of an external argument inside a function by passing a pointer to it. In Swift, a similar method is provided, but the parameters need to be modified with inout as follows:

The value of number was originally 10, but was changed to 20 by the inoutFunc call. So how does inout change the value of the external argument? There is a saying that the same as OC, using a pointer to change the value; It is also said that inout is a function at the bottom that reassigns external arguments to values inside the function it modifies. In view of these two statements, we can verify through assembly, this is the use of real machine debugging, so the use of ARM assembly.

The diagram aboveLine 12and22The breakpoint is opened and XCode assembly debugging is openedDebug -> Debug Workflow -> Always show Disassembly. To run the project, first enter the breakpoint at line 22:The red box in the figure isinoutFuncA line of code can be found on line 28 above where the function is calledldr x0, [sp, #0x10][sp, #0x10]; [sp, #0x10]sp+#0x10That is, register X0 now stores an address that passes throughregister read x0Command to change the IP address tox0 = 0x000000016dbf9a80.

Step into the inoutFunc function and get the following code:

X0 = 0x000000016DBF9a80 = 0x000000016DBF9a80 = 0x000000016DBF9a80 = 0x000000016DBF9a80 = 0x000000016DBF9a80 = 0x000000016DBF9a80 = 0x000000016DBF9a80 = 0x000000016DBF9a80

The value 0x000000000000000A in the red box is exactly 10 in decimal form. Go to line 6 of assembly code, store what the x0 address points to in register X8, and increment the value by 10, thus completing the change to the value of the external argument. There is no reassignment of number after inoutFunc is called in viewDidLoad, confirming that inout changes the value of the external argument via address passing.

Two points to note when using inout:

  • 1. Inout can only be passed in constants and literals that can be assigned multiple times
  • 2. Inout cannot modify mutable parameters

Function overloading

Function overloading refers to the function name is the same, but different parameter name | | parameter types different | | parameter number different | | parameters different tags. It should be noted that function overload and function overriding are two different concepts. Function overriding involves inheritance relationships, while function overloading does not. Also, there are no overloads of functions or methods in OC, only overrides. Here are a few examples of function overloading:

As you can see, four functions with the same method name but different parameters do not actually report an error, which is method overloading.

However, there are caveats to method overloading:

  • Method overloading has nothing to do with the return value of a function, that is, if the function names and parameters are identical, if the return value is different, it does not constitute a function overload, and the compiler will report an error.

As shown in the figure, when a method is called, the compiler does not know which function to call and therefore reports an ambiguous error.

  • Method overloading versus default parameter values

As you can see from the figure, the second function is called in the same form as the first function because it sets the default value for c, but the compiler does not give an error here, assuming that the second function also has a test(a:, b:, c:) call form.

Inline functions

An inlined function is a function that is optimized by the compiler after compiler inlining is enabled. The optimization will extract the function body and call it directly, without giving the function any more stack space.

func test(a) {
    print("test123")
}
test()
Copy the code

As shown in the above function, when test() is called, stack space needs to be opened for it, and only one print function is called internally, so print function may be directly called when inlining optimization is enabled.

The following figure shows how to enable inline optimization: DebugOptimization is disabled by default.ReleaseIt is enabled by default. In order to test the phenomenon of inline optimization, we will first takeDebugMode turns on optimization, then interrupts the test() call, and runs the project again to find that it prints directlytest123And then intestFunction internal interrupt point, enter assembly as follows:Global search found nonetestFunction call, but directly calledprintFunction.

Inline optimization, however, does not optimize all functions. The following points are not optimized:

  • Function body code is too much
  • There are recursive calls to the function
  • Functions contain dynamic distributions, such as polymorphic calls to classes and subclasses

Inline functions also have inline arguments that control @inline(never) and @inline(__always).

  • use@inline(never)Modifier, which does not inline even if compiler optimization is turned on
  • use@inline(__always)Modifier, when compiler optimization is enabled, even if the function body code is long, it will be inlined, but recursion and dynamic distribution will not be optimized

5. Function types

Each function can conform to a function type, for example:

func test(a) {
    print("test123"} corresponds to () -> ()func compute(a:Int = 8.b: Int = 9) -> Int {
    return a+b; The corresponding (}Int.Int) - >Int

Copy the code

In the above code, () -> () and (Int, Int) -> Int represent a function type. You can find that function types do not need parameter names, just specify the parameter types.

Function types can also be used as arguments to functions and as return values. Functions that use function types as return values are called higher-order functions, for example:

// Function type as argument
func testFunc(action: (Int) - >Int) {
    var result = action(2)
    print(result)
}

func action(a:Int) -> Int {
    return a
}
testFunc(action: action(a:))

// Function type as return value
func action(a:Int) -> Int {
    return a
}
func testFunc(a)- > (Int) - >Int {
    return action(a:)
}
let fu = testFunc()
print(fu(3))

Copy the code

Nested functions

In Swift, you can define functions inside functions, called nested functions, as shown in the following code:

func forward(_ forward: Bool)- > (Int) - >Int {
    func next(_ input: Int) -> Int {
        input + 1
    }
    func previous(_ input: Int) -> Int {
        input - 1
    }

    return forward ? next : previous
}
Copy the code

The purpose of defining other functions inside a function like the one above is to encapsulate the internal implementation of the function, so that the external implementation only sees that the forward is called without knowing the internal implementation logic, and of course, the internal nested function cannot be called directly.

conclusion

Compared with OC, the following points are mainly added to Swift:

  • Parameters of the label
  • Function overloading
  • Nested function

In general, I feel that Swift functions are more convenient to use and parameter labels make the code more readable. The above is the summary of Swift function, if there are any shortcomings, welcome to point out.