2017-02-28 19:26:47 LFYPhoenix 阅读数 282

闭包

       闭包是自包含的功能块,可以在代码中传递和使用

       闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。Swift处理所有的捕获的内存管理。

全局函数和嵌套函数实际上是闭包的特殊情况:

    全局函数是具有名称并且不捕获任何值的闭包。

    嵌套函数是具有名称的闭包,并且可以从其封闭函数捕获值。

 

 

1.闭包表达式

    闭包表达式的一般形式:

    {parameters - > return type in

            语句

   }}

         闭包的主体的开始由in关键字引入。in关键字表示闭包的参数和返回类型的定义已完成,闭包的主体即将开始。

         闭包表达式中的参数可以是inout参数,但它们不能具有默认值;可以是可变参数;元组也可以用作参数类型和返回类型。

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

var reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in

    //闭包的主体

    return s1 > s2

})

print(reversedNames)//["Ewa", "Daniella","Chris", "Barry", "Alex"]

 

 

2.单表达式闭包的隐式返回

单表达式闭包可以通过在其声明中省略return关键字来隐式返回其单个表达式的结果

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

 

 

3.速记参数名称

     Swift自动为内联闭包提供了速记参数名称,可以用来通过名称$ 0$ 1$ 2等引用闭包的参数的值。

            如果在闭包表达式中使用这些速记参数名称,则可以从其定义中省略闭包的参数列表,并且将从预期的函数类型推断速记参数名称的数量和类型, 也可以省略in关键字.

reversedNames = names.sorted(by: { $0 > $1 } )

 

//更简单的运算符方法

reversedNames = names.sorted(by: >)

 

 

4.尾随闭包

 

funcsomeFunctionThatTakesAClosure(closure: () -> Void) {

    //函数体

}

//不使用尾随闭包调用函数

someFunctionThatTakesAClosure(closure: {

    //闭包主体

})

 

//使用尾随闭包调用函数

someFunctionThatTakesAClosure() {

    //尾随闭包主体

}

 

 

5.捕获值

  闭包可以从定义它的上下文捕获常量和变量。然后,闭包可以引用并修改那些常量和变量的值,即使定义常量和变量的原始作用域不再存在。

  Swift中,可以捕获值的闭包的最简单形式是嵌套函数。嵌套函数可以捕获其任何外部函数的参数,也可以捕获外部函数中定义的任何常量和变量。

 

6.闭包是引用类型

无论何时将函数或闭包分配给常量或变量,实际上都将该常量或变量设置为函数或闭包的引用。如果给两个不同的常量或变量赋值一个闭包,这两个常量或变量都将引用同一闭包。

 

 

7.逃逸闭包

当闭包作为参数传递给函数时,闭包被称为逃逸函数,但在函数返回后闭包被调用。

当声明一个函数将一个闭包作为其参数之一时,可以在参数的类型之前写入@escaping来表示允许闭包逃逸。@escaping标记闭包意味着你必须在闭包内自我引用

//闭包逃逸的一种方式是通过存储在函数外部定义的变量中

var completionHandlers:[() -> Void] = []

//someFunctionWithEscapingClosure_ :)的闭包是一个转义闭包,它需要自我引用

funcsomeFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {

    completionHandlers.append(completionHandler)

}

 

//someFunctionWithNonescapingClosure_ :)的闭包是一个非转义闭包,它可以自我引用

funcsomeFunctionWithNonescapingClosure(closure: () -> Void) {

   closure()

}

 

class SomeClass {

    var x = 10

    func doSomething() {

        someFunctionWithEscapingClosure { self.x = 100 }

        someFunctionWithNonescapingClosure { x = 200 }

   }

}

 

let instance = SomeClass()

instance.doSomething()

print(instance.x)

 

completionHandlers.first?()

print(instance.x)

//Prints "100"

 

8.自动闭包

//autoclosure是一个闭包,它被自动创建以包装一个表达式,该表达式作为参数传递给函数。它不接受任何参数,当它被调用时,它返回包装在其中的表达式的值。

var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

print(customersInLine.count)//5

 

let customerProvider = {customersInLine.remove(at: 0) }

print(customersInLine.count)//5 因为customerProvider的隐式autoclosure使程序进行延迟操作,因为里面的代码不会运行,直到你调用闭包。

 

print("Now deleting \(customerProvider())!")//Now deleting Chris! //这里调用闭包,才会真正删除元素

print(customersInLine.count)//4

 

//显示自动闭包

var customers = ["Alex", "Ewa", "Barry", "Daniella"]

func serve(customercustomerProvider: () -> String) {

    print("Now serving \(customerProvider())!")//Now serving Alex!

}

serve(customer: { customers.remove(at: 0) } )

 

//使用@autoclosure属性标记其参数的类型来进行自动闭包

var customers2 = ["Alex", "Ewa", "Barry", "Daniella"]

func serve2(customercustomerProvider: @autoclosure () -> String) {

    print("Now serving \(customerProvider())!")

}

serve2(customer: customers2.remove(at: 0))//Now serving Alex!

 

//如果希望允许自动隐藏,可同时使用@autoclosure@escaping属性。

var customersHide = ["aaaa", "bbbb", "cccc", "dddd"]

var customersClosure:[() -> String] = []

let customerCollect = { customersHide.remove(at: 0) }

funccollectCustomerProviders(_ customerCollect: @autoclosure@escaping () -> String) {

    customersClosure.append(customerProvider)

}

collectCustomerProviders(customersHide.remove(at: 0))

collectCustomerProviders(customersHide.remove(at: 0))

 

print("Collected \(customersHide.count) closures.")//Collected 4 closures.

for customersHide in customersClosure {

    print("Now serving \(customerCollect())!")

}

/*

 Nowserving aaaa!

 Nowserving bbbb!

 */

2017-10-18 18:23:24 bddzzw 阅读数 10342
/*
Swift 中的闭包有很多优化的地方
1 根据上下文推断参数和返回值的类型
2 从单行表达式闭包中隐式返回 可以省略return
3 可以使用简化的参数如 $0 $1 意为从0或者1开始
4 提供了尾随闭包的语法
*/
//语法   parameters参数 return 隐藏了
//{(parameters) -> return type in
//    parameters
//}
//最简单的闭包//省略in的
let b = {
    print("这也是闭包")
}

//用变量记录函数 (带参数的闭包)
//带有参数的闭包
//参数返回值 实现代码  {形参->返回值 in 代码}
//带参数待返回值的闭包
let countNum = {(num1:Int,num2:Int)->Int in
    return num1+num2;
}
let count1 = countNum(2,3)


//闭包的应用场景

/*异步执行完成回调  控制器之间的回调  自定义视图的回调*/

/*  以下代码需要在项目中的.Swift文件中完成
override func viewDidLoad() {
super.viewDidLoad()
loadData { (result) in
print("获取json信息\(result)")
}
// Do any additional setup after loading the view, typically from a nib.
}
func loadData(completion: @escaping (_ result: [String])->()) -> () {
DispatchQueue.global().async {
print("耗时操作\(Thread.current)")
Thread.sleep(forTimeInterval: 1.0);
let json=["12","23","34"]
DispatchQueue.main.async(execute: {
print("主线程\(Thread.current)")
completion(json)
})
}
}
结果为:耗时操作<NSThread: 0x600000277000>{number = 3, name = (null)}
主线程<NSThread: 0x604000075a80>{number = 1, name = main}
获取json信息["12", "23", "34"]
*/

//闭包表达式
let names = ["s","b","e","h","f"]

func backwards(a1:String,a2:String)->Bool{
    return a1<a2;
}
// public func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
var result = names.sorted(by:backwards)
print(result)

//参数名缩写
///以上代码还可以  Swift自动内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。
var result1 = names.sorted(by:{$0<$1})
print(result1)

//作为一个函数接受两个String类型的参数并返回Bool类型的值Swift可以自动推断出您想使用大于号的字符串函数实现:
//运算符函数
var result2 = names.sorted(by:<)
print(result2)

//尾随闭包
//例子1  尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。

var result3 = names.sorted(){$0<$1}
print(result3)



//例子2
//此时点回车函数会变成中括号的形式 也就是说如果函数的最后一个参数是闭包,函数的参数可以提前结束
//        最后一个参数直接使用{}来包装闭包的代码
//        loadData1(completion: <#T##([String]) -> ()#>)
//以下两段代码相同只不过一个是使用尾随闭包的写法
/*func loadData(completion:@escaping (_ result:([String])->())->()){
    DispatchQueue.global().async {
        print("耗时操作\(Thread.current)")
        Thread.sleep(forTimeInterval: 1.0);
        let json=["12","23","34"]
        //以下两段代码相同只不过一个是使用尾随闭包的写法
        DispatchQueue.main.async{
            print("主线程\(Thread.current)")
            completion(json)
        }
        DispatchQueue.main.async(execute: {
            print("主线程\(Thread.current)")
            completion(json)
        })
        
    }
}
*/


良言一句三冬暖,恶语伤人六月寒。无论工作还是生活,都不要拿脾气当做与他人博弈的武器。即使侥幸一时赢了,最终也只是两败俱伤。一言一语间,完成的是沟通,体现的是修养。或许我们不能成为优秀的别人,却完全可以做更好的自己。
2015-12-23 11:34:22 jaccty 阅读数 403

       Swift 中的闭包定义是:闭包是自包含的匿名函数代码块,可以作为表达式、函数参数和函数返回值,闭包表达式的运算结果是一种函数类型。Swift中的闭包类似于Objective-C 中的代码块block、Java中的匿名内部类。

 使用闭包表达式

Swift中的闭包表达式很灵活,其标准语法格式如下:

{ (参数列表) ->返回值类型in

    语句组

}

其中,参数列表与函数中的参数列表形式一样,返回值类型类似于函数中的返回值类型,但不同的是后面有in关键字。Swift提供了多种闭包简化写法,我来介绍下面几种不同形式:

 

1、类型推断简化

类型推断是Swift的强项,Swift可以根据上下文环境推断出参数类型和返回值类型。以下代码是标准形式的闭包:

{(a:Int, b:Int) -> Int in    
return a + b
}

Swift能推断出参数a和b是Int类型,返回值也是Int类型。简化形式如下:

{(a, b) in return a + b }
{a, b in return a + b }  //参数列表括号也可以省略

2、隐藏return关键字

在闭包内部语句组只有一条语句,如return a + b等,那么这种语句都是返回语句。前面的关键字return可以省略,省略形式如下:

{a, b in a + b }

使用这种简化方式修改后的示例代码如下:

 

func calculate(str :String)-> (Int,Int)-> Int {  
    var result : (Int,Int)-> Int  
     
    switch (str) {  
    case "+" :  
        result = {a, b in a + b } //return关键字省略  
    default:  
        result = {a, b in a - b } //return关键字省略 
    }  
    return result  
}  

省略的前提是闭包中只有一条return语句。

 

3、省略参数名称

Swift提供了参数名省略功能,我们可以用$0、$1、$2…来指定闭包中参数,$0指代第一个参数,$1指代第二个参数,$2指代第三个参数,以此类推$n+1指代第n个参数。

使用参数名省略功能,在闭包中必须省略参数列表定义,Swift能够推断出这些缩写参数的类型。参数列表省略了,in关键字也需要省略。参数名省略之后如下所示:

{$0 + $1}

使用参数名省略后的示例代码如下:


func calculate(str :String)-> (Int,Int)-> Int {
var result : (Int,Int)-> Int
switch (str) {
case "+" :
result = {$0 + $1} //参数名省略
default:
result = {$0 - $1} //参数名省略
}
return result
}
let s1:(Int,Int)-> Int = calculate("+")
print("10 + 10= \(s1(10,10))")
let s2:(Int,Int)-> Int = calculate("-")
print("10 - 10 = \(s2(10,10))")

4、使用闭包返回值

闭包表达本质上是函数类型,是有返回值的,我们可以直接在表达式中使用闭包的返回值。重新修改add和sub闭包,示例代码如下:

let a1:Int = {(a:Int, b:Int) -> Int in
return a + b
}(10,10) 

print("10 + 10= \(a1)")
 

注:给a1赋值,后面是一个闭包表达式。但是闭包表达式不能直接赋值给a1,因为a1是Int类型,需要接收Int类型,而闭包的返回值为Int类型。这就需要在闭包结尾的大括号后面接一对小括号(10,10),通过小括号(10,10)为闭包传递参数。


参考自The Swift Programming Language 官方文档

转载请注明   转载jaccty的博客


2015-10-14 12:50:31 th_gsb 阅读数 299

【前言】

根据上一节的例子,我们讲解此次闭包的编写

上节例子:


【格式】

{(参数名称:参数类型)->返回类型 in 闭包函数体}

【举例】


【闭包函数简化】

1.由于AutoAdd函数中addFunc这个参数的传入参数类型和返回类型为Int,那么swift会推断编写的闭包函数也是一样,所以此处可以将参数类型和返回值类型简化掉

AutoAdd(&c, addFunc:{
<span style="white-space:pre">	</span>(var num) in 
<span style="white-space:pre">	</span>return num + 3
})

2.由于AutoAdd函数中addFunc这个参数的传入参数数目为一个,那么swift会自动为这个参数命名为“$0”,所以我们可以将参数部分简化掉

AutoAdd(&c, addFunc:{
<span>	</span>return $0 + 3
})


3.由于返回类型已知为Int,那么将return关键字简化掉

AutoAdd(&c, addFunc:{ $0 + 3 })
【总结】

闭包函数大大减化了函数的编写,使得开发人员工作更快,节省敲代码的时间。

大家加油!继续支持swift语言!


2017-03-10 19:00:29 Reflection_ 阅读数 177
                              闭包

1: Swift闭包定义:闭包是自包含的匿名函数代码块,可以作为表达式,函数参数和函数返回值。闭包表达式的运算结果是一种函数类型。Swift中的闭包可以捕获和存储其所在上下文环境中的常量和变量,然后进行一系列的简化。
2:格式 swift的闭包表达式很灵活,其标准语法格式如下:
{(参数列表)->返回值类型 in
语句组
}
其中参数列表与函数参数列表形式一样,返回值类型类似于函数中的返回值类型,但不同的是后面有in关键字。
3:类型推断简化
类型推断简化是swift的强项,swift可以根据上下文环境推断出参数类型和返回值类型,以下代码是标准形式的闭包:
{(a:Int,b:Int)->Int in
return a+b
}
swift能推断出参数a和b是Int类型,返回值也是Int 类型,简化形式如下:
{(a,b)in return a+b }
{a,b in return a+b} //参数列表括号也可以省略
4:隐藏return关键字
如果在闭包内部语句组只有一条语句,如return a + b等,那么这种语句都是返回语句。前面的关键字return可以省略。省略形式如下:
{ a,b in a + b}
注意:省略的前提是闭包中只有一条return 语句,下面这种有多条语句的情况下是不允许的:
{a , b in var c = 0; a + b} 这个是错误的
5:省略参数名
前面的闭包表达式已经很简洁了,不过swift闭包还可以再进行简化。Swift提供了参数名省略功能,我们可以用01、2......0指代第一个参数,$1指代第二个参数,以此类推。使用参数名省略功能,在闭包中必须省略参数列表定义,swift能够推断出这些缩写参数的类型。参数列表省略了,in 关键字也需省略。
对比如下:
~~
result = {
(a: Int ,b:Int ) -> Int in
Return a - b
}
省略参数名之后变为:
~

result = { 01}

6:使用闭包返回值
闭包表达本质上是函数类型,是有返回值的,我们可以直接在表达式中使用闭包的返回值。理解闭包返回值有一个窍门,就是将闭包部分看成一个函数。如图所示把灰色部分替换为函数,那么函数调用时后面是小括号的参数列表。
例1:Let c1: Int = {(a:Int , b:Int ) ->Int in
return a - b
}(10,5)
上述代码有两个表达式,第一行是给c1赋值,后面是一个闭包表达式。但是闭包表达式不能直接赋值给c1 ,因为c1是Int型,需要闭包的返回值,这就需要在闭包结尾的大括号后面接一对小括号(10,5),通过小括号(10,5)为闭包传递参数。通过这种方法可以直接为变量和常量赋值,这在有些情况下使用起来非常方便。
7:使用尾随闭包
闭包表达式可以作为函数的参数传递,如果闭包表达式很长,就会影响程序的可读性,尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
例2: func calculate (opr: String , funN:(Int ,Int )-> Int ){
~~
}
caculate(“+”,funN:{(a: Int ,b: Int)-> Int in return a + b } )
Caculate(“+”) { (a: Int ,b: Int ) ->Int in return a + b}
Caculate (“+”) { 0 + 1}

第一行定义了caculate 函数,其中最后一个参数funN是(Int ,Int )->Int 函数类型,funN可以接受闭包表达式,省略部分是调用过程,{(a: Int ,b: Int)-> Int in return a + b }是传递的参数,这个参数很长,我们可以使用灰色部分代码形式,将闭包表达式移到()之外,这种形式就是尾随闭包。
注:如果闭包表达式不是最后一个参数,就不能使用尾随闭包写法了。
如:例2: func calculate (opr: String, funN:(Int ,Int )-> Int )中的opr: String与funN:(Int ,Int )-> Int交换位置 ,变成func calculate( funN:(Int ,Int )-> Int,opr: String),其中闭包表达式不是最后一个参数,就不能使用尾随闭包写法了。
8:区分函数与闭包
闭包中往往有一些关键字,例如in,还有缩写参数 0,1 ……等等,这些特征是在函数中没有的。

Swift 函数与闭包

阅读数 637

没有更多推荐了,返回首页