Swift4 基础部分:Closures

本文是学习《The Swift Programming Language》整理的相关随笔,基本的语法不作介绍,主要介绍Swift中的一些特性或者与OC差异点。

系列文章:

  • Swift4 基础部分:The Basics
  • Swift4 基础部分:Basic Operators
  • Swift4 基础部分:Strings and Characters
  • Swift4 基础部分:Collection Types
  • Swift4 基础部分:Control Flow
  • Swift4 基础部分:Functions

Closures

闭包表达式语法(Closure Expression Syntax)

Closure expression syntax has the following general form:

 { (parameters) -> return type in
    statements
}

例子:数组排序的例子

var names:[String] = ["B","A","C"];
names = names.sorted(by: {
    (num1:String,num2:String) -> Bool in
    return num1 < num2;
});
print(names);

执行结果:

["A", "B", "C"]

上下文检测类型(Inferring Type From Context)

Because the sorting closure is passed as an argument to a 
method, Swift can infer the types of its parameters and 
the type of the value it returns. The sorted(by:) method 
is being called on an array of strings, so its argument 
must be a function of type (String, String) -> Bool. This 
means that the (String, String) and Bool types do not need 
to be written as part of the closure expression’s 
definition.
  • 排序的闭包因为Swift中的类型检测机制,所以可以省掉写入String,-> Bool

针对上述的例子做简化:

var names:[String] = ["B","A","C"];
names = names.sorted(by: {
    (name1,name2) in
    return name1 < name2;
});
print(names);

单表达式闭包的隐式返回(Implicit Returns from Single-Expression Closures)

Single-expression closures can implicitly return the 
result of their single expression by omitting the return 
keyword from their declaration
  • 单表达式的闭包可以省略掉return关键字

继续简化上述例子:

var names:[String] = ["B","A","C"];
names = names.sorted(by: {
    (name1,name2) in name1 < name2;
});
print(names);

参数名称缩写(Shorthand Argument Names)

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
  • 结合闭包中类型的检测,闭包中的参数名可以使用$0, $1, $2代替

继续简化上述例子:

var names:[String] = ["B","A","C"];
names = names.sorted(by: {
    $0 < $1;
});
print(names);

操作方法(Operator Methods)

There’s actually an even shorter way to write the closure 
expression above. Swift’s String type defines its string-
specific implementation of the greater-than operator (>) 
as a method that has two parameters of type String, and 
returns a value of type Bool.
  • 继续简化可以直接用>,<表示比较结果

继续简化例子:

var names:[String] = ["B","A","C"];
names = names.sorted(by:<);
print(names);

尾随闭包(Trailing Closures)

If you need to pass a closure expression to a function as 
the function’s final argument and the closure expression 
is long, it can be useful to write it as a trailing 
closure instead. A trailing closure is written after the 
function call’s parentheses, even though it is still an 
argument to the function. When you use the trailing 
closure syntax, you don’t write the argument label for the 
closure as part of the function call.
  • 当闭包是函数中的最后一个参数时,函数调用可以省略掉参数标签的写法,简化函数

闭包是引用类型数据(Closures Are Reference Types)

In the example above, incrementBySeven and incrementByTen 
are constants, but the closures these constants refer to 
are still able to increment the runningTotal variables 
that they have captured. This is because functions and 
closures are reference types.
  • Swift中的闭包是引用类型的数据

例子:

var num = 0;
func increment(completion:() -> Void){
    completion();
    print("num:\(num)");
}
increment {
    num += 10;
}
let referIncrement = increment;
referIncrement{
    num += 20;
}

执行结果:

num:10
num:30

逃逸闭包(Escaping Closures)

A closure is said to escape a function when the closure is 
passed as an argument to the function, but is called after 
the function returns. When you declare a function that 
takes a closure as one of its parameters, you can write 
@escaping before the parameter’s type to indicate that the 
closure is allowed to escape.
  • Swift中如果需要逃逸闭包需要利用关键字@escaping修饰

例子:

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}

class SomeClass {
    var x = 10
    func doSomething() {
        
        someFunctionWithEscapingClosure(completionHandler: {
            self.x = 100;
        });
        
        someFunctionWithNonescapingClosure(closure: {
            x = 200;
        });
        
        // 以下的调用方式一样可行,同时说明了尾随闭包的使用
        //someFunctionWithEscapingClosure { self.x = 100 }
        //someFunctionWithNonescapingClosure { x = 200 }
    }
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
completionHandlers.first?()
print(instance.x)

执行结果:

200
100

自动闭包(Autoclosures)

An autoclosure is a closure that is automatically created 
to wrap an expression that’s being passed as an argument 
to a function. It doesn’t take any arguments, and when 
it’s called, it returns the value of the expression that’s 
wrapped inside of it.
  • Swift中的自动闭包能动态的封装一个表达式为一个函数的参数,自动闭包不能带任何的参数

例子:


var num = 1;
func filter(contions:() -> Bool){
    if contions(){
        num += 3;
        print("num:\(num)");
    }else{
        num += 1;
        print("num:\(num)");
        filter(contions: {num % 3 == 0})
    }
}
filter(contions: { num % 3 == 0 })

执行结果:

num:2
num:3
num:6

下面开始利用@autoclosure简化:

var num = 1;
func filter(_ contions: @autoclosure () -> Bool){
    if contions(){
        num += 3;
        print("num:\(num)");
    }else{
        num += 1;
        print("num:\(num)");
        filter(num % 3 == 0)
    }
}
filter(num % 3 == 0)
Overusing autoclosures can make your code hard to 
understand. The context and function name should make it 
clear that evaluation is being deferred.
  • autoclosure的过度使用并不好,会让代码逻辑看起来更难理解,必须了解上下文中函数的定义才可结合使用

你可能感兴趣的:(Swift4 基础部分:Closures)