Swift中闭包介绍和使用

闭包是自包含的函数代码块,可以在代码中传递和使用。闭包表达式是一种利用间接语法构建内联闭包的方式。
闭包的表达式(含闭包参数)

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

在这里关键字in表示闭包的参数和返回值类型已经完成,闭包函数体即将开始。

/*无参数形式的闭包表达式语法形式如下:
{() -> 返回值类型 in 
}
定义的语法:
let/var  闭包表达式常量名称/闭包表达式变量名称 = 无参数的表达式
调用方法:
闭包表达式常量名称/闭包表达式变量名称()*/
let printStr = { () ->Void in
    print("Swift的闭包")
    
}
printStr()
/*
有参数形式的闭包表达式语法形式如下:
{(参数列表) -> 返回值类型 in 
    语法块
}
定义的语法:
let/var  闭包表达式常量名称/闭包表达式变量名称 = 有参数的表达式
调用方法:
闭包表达式常量名称/闭包表达式变量名称(参数列表)*/
*/
let add = { (x:Int,y:Int) ->Int in
    return x+y
}

print(add(10,20))

上面主要对闭包的定义进行的介绍,其实闭包表达式最常用于其他函数中,并不是单独去使用。
1、把闭包表达式作为函数的参数

//定义函数,将闭包表达式放到函数的参数里面
func copare (arr:[Int],value:Int,cb:(_ Num:Int,_ Value:Int)->Bool)->Bool{
    for item in arr{
        if(cb(item,value)){
            return true;
        }
    }
    return false;
}
let array = [20,90,100,50,60]
//调用函数并且实现完成闭包表达式的代码块
let v1 = copare(arr: array, value: 100) { (num:Int, value01:Int) -> Bool in
    return num > value01
};

可以从上面的copare函数中可以看出第三个参数是一个闭包闭包的类型为(Num:Int,Value:Int)->Bool
注意:
(1)在调用函数时可以省略闭包的返回值
(2) 如果标保中只有一行代码,那么可以省略掉return
2、Trailing闭包:如果开发者需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用Trailling闭包,他可以增前函数的可读性。


//例子 一
let arrty:Array = [10,90,80,20]
//方法的最后一个参数为(_ Num:Int,_ value:Int)->Int
func trailingClosure01(array arr:[Int],closure:(_ Num:Int,_ value:Int)->Int){
    for item in arr {
        print(closure(10,item))
    }
    
}
//此为不使用traling闭包的函数调用
trailingClosure01(array: arrty, closure: {(num1:Int,num2:Int)->Int in
    return num2+num1;
})
//此为是使用traling闭包的函数调用
trailingClosure01(array: arrty) { (num1, num2) -> Int in
    return num2 - num1
}

//例子二
func trailingClosure02(closure: ()->Void)->Void{
    closure()
}
//此为不使用traling闭包的函数调用
trailingClosure02(closure: {()->Void in
     print("没有使用traling闭包调用函数")
})
//此为是使用traling闭包的函数调用
trailingClosure02() {
    print("使用traling闭包调用函数")
}

3、捕获值:闭包可以自起定义的上下文中捕获常量和变量

/*
 例子1、该函数的返回值是闭包(闭包是没有参数,返回值为Int)
 */
func captureValue(forIncrement amount:Int)->()->Int
{
    var runningTotal = 0;
    /*
     //这是没有使用tralling包的定义包
    return {
        ()->Int in
        runningTotal += amount
        return runningTotal};*/
    //定义函数 captureValueClosure()
    func captureValueClosure()->Int{
        runningTotal += amount
        return runningTotal
    }
    return captureValueClosure;
    //上面两个return可以看出闭包是自包含的函数代码块
}

let value1 = captureValue(forIncrement: 10);
print(value1())
print(value1())
print(value1())
print(value1())
print(value1())

4、下面写一种闭包表达式在UI程序中的使用的例子,如图:

closure.gif

自定义的View的代码如下:

import UIKit
//创建一个闭包类型
typealias ClosureClick = ()->Void;
class TestView: UIView {
    override func willMove(toSuperview newSuperview: UIView?) {
        let btnChangSuperBackgroundColor = UIButton.init(frame: CGRect(x: 10, y: 130, width: (newSuperview?.frame.size.width)! - 20, height: 40))
        btnChangSuperBackgroundColor.backgroundColor = UIColor.blue;
        btnChangSuperBackgroundColor.setTitle("点击修改父窗口的颜色", for: .normal)
        self.addSubview(btnChangSuperBackgroundColor);
        
        btnChangSuperBackgroundColor.addTarget(self, action:#selector(TestView.btnClick), for:.touchUpInside );
    }
    func btnClick() -> Void {
        //在这里调用闭包
        if (myClosure != nil) {
            myClosure!()
        }
    }
    //为自定义的VIew 创建一个闭包的类型的属性
    var myClosure:ClosureClick?

}

UIViewController中实现的代码如下:

override func viewDidLoad() {
        super.viewDidLoad()
        
        let testView  = TestView();
        //用来点击按钮后实现随机颜色的数组
        let colorArray = [UIColor.red,UIColor.black,UIColor.blue]
        testView.frame = CGRect(x: 0, y: 20, width: self.view.bounds.size.width, height: 300)
        testView.backgroundColor = UIColor.brown
        //在这里实现闭包表达式
        testView.myClosure = {
            let index:Int  = Int(arc4random_uniform(3));
            self.view.backgroundColor = colorArray[index];
        }
        
        self.view.addSubview(testView);
    }

5、Swift中闭包的循环引用
循环引用可以简单的理解为A引用了B,而B又引用A双蛋都同时保持对方的一个引用,在释放的时候A和B都会的等待对方先释放,这样两个都不会释放,造成内存的泄露,并且如果过于频繁或者两者的处理量比较大时会发生崩溃。如何判断类的循环引用,需要重新类的析构函数如下:

deinit {
        print("销毁了"+NSStringFromClass(self.classForCoder));
    }

以下为几种常见的对循环引用的解决方案。
方案一:
仿照OC 解决处理循环引用用weak进行修饰,将上面的中的闭包的实现修改,建议在开发总使用该解决方案
方案二:
处理循环引用[weak self]来完成
方案三:
处理循环引用[unowned self]
三种方案的具体代码如下:

import UIKit
//创建一个闭包类型
typealias ClosureClick = ()->Void;
class TestView: UIView {
    //为自定义的VIew 创建一个闭包的类型的属性
    var myClosure:ClosureClick?
    //给类添加一个属性
    var classNum:Int?
    //这里就不用提前调用闭包了
    var testClosure:((Int)->Void)?
    func btnClick() -> Void {
        //在这里调用闭包
        if (myClosure != nil) {
            myClosure!()
        }
    }
    func testC(myNum:Int) -> Void {
        //产生循环引用的
        testClosure = {(myNum)->Void in
            self.classNum = myNum;
        }
        //方案1
        weak var weakSelf = self
        testClosure = {(myNum)->Void in
            weakSelf?.classNum = myNum;
        }
        //方案2
        //[weak self] 表示 self为可选型 可以为nil 所以在使用的时候必须解包
        testClosure = {[weak self](myNum)->Void in
            self?.classNum = myNum;
        }
        //方案3
        //[unowned self]由于在使用前要保证一定有这个对象 所以不必解包
        testClosure = {[unowned self](myNum)->Void in
            self.classNum = myNum;
        }
        
    }
    deinit {
        print("销毁了"+NSStringFromClass(self.classForCoder));
    }

}

类的创建和调用:

 var testView:TestView? = TestView()
        //[unowned self]
        testView?.testC(myNum: 10)
        testView = nil
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容