Swift4 基础部分:Closures

本文是学习《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的过度使用并不好,会让代码逻辑看起来更难理解,必须了解上下文中函数的定义才可结合使用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.前言: Swift包含了 C 和 Objective-C上所有基础数据类型,Int表示整型值; Double和...
    廖马儿阅读 1,735评论 0 0
  • 86.复合 Cases 共享相同代码块的多个switch 分支 分支可以合并, 写在分支后用逗号分开。如果任何模式...
    无沣阅读 5,289评论 1 5
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 9,403评论 1 10
  • 以下翻译自Apple官方文档,结合自己的理解记录下来。翻译基于 swift 3.0.1 原文地址 Closure...
    艺术农阅读 5,519评论 0 3
  • 妈妈带着妞妞来园里玩,妞妞很是兴奋,到处跑来跑去,一会儿钻到海洋球里,一会儿骑到小老虎车上飞快地跑,妈妈跟...
    未央之雨阅读 3,767评论 0 0