本文是学习《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的过度使用并不好,会让代码逻辑看起来更难理解,必须了解上下文中函数的定义才可结合使用