本文是學習《The Swift Programming Language》整理的相關隨筆,基本的語法不作介紹,主要介紹Swift中的一些特性或者與OC差異點。
系列文章:
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的過度使用并不好,會讓代碼邏輯看起來更難理解,必須了解上下文中函數的定義才可結合使用