Swift闭包(7)

教程目录
与OC一样的内容不重复介绍

闭包

闭包其实和OC中的Block差不多,作用是一样的.下面说一下主要的用法和注意事项.
所有要说的话全在代码里

闭包的表现形式
{ (parameters) -> return type in
      statements
}
定义全局的闭包
import UIKit

class BlockViewController: UIViewController {

    //定义一个全局的无参无返回值的block
    let block = {() -> () in
        print("调用无参无返回值的block");
    }
    //有参无返回值
    let blockParam = {(s: String) -> () in
        print("调");
    }
    //无参有返回值
    let blockRuturn = {() -> String in
        return "无参数有返回值"
    }
    //有参数有返回值
    let blockParamRuturn = {(s: String) -> (String) in
        return "返回值"+s
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        block();
        blockParam("有参数");
        // Do any additional setup after loading the view.
    }
}
闭包作为参数
import UIKit

class BlockViewController: UIViewController {
   
    override func viewDidLoad() {
        super.viewDidLoad()               
        blockTest();
        blockAsParam(str: "字符串", success: {
            //第一个闭包
        }, error: {
            //正常情况blockTwo会被省略掉,但是我不省略,否则看起来代码不容易辨识,当然看个人情况
        })
        
        blockAsParamAndParam(successBlock: { (content, status) in
            print("\(content)状态码\(status)")
        }, errorBlock: {(content,status) in
            print("\(content)状态码\(status)")
        })
        
        blockParamAndReturn(successBlock: { (successContent, status) -> (String) in
            
            let str = "\(successContent)状态码为\(status)返回告诉他成功了我很高兴"
            return str;
            
        },errorBlock: { (errorContent, status) -> (String) in
            
            let str = "\(errorContent)状态码为\(status)返回告诉他失败了无所谓,但是需努力"
            return str;
        })
        ///逃逸闭包
        blockEscapingTest();

        // Do any additional setup after loading the view.
    }
       
    func blockTest() {
        
        //定义一个简单的局部block,
        let appendBlock = {(orignStr: String,appendStr: String) -> String in
            return orignStr + appendStr;
        }
        let orginStr = "原始字符串";
        let appendStr = "新添加的字符串";
        let newStr = appendBlock(orginStr,appendStr);
        print(newStr);
        //通过上面的例子可以多得出一个结论,Swift是值传递
        
        //调用全局的block
        block();
        blockParam("调用有参无返回值的block");
        print(blockRuturn());
        print(blockParamRuturn("有参数"));

    }
    
    //无参数无返回值闭包作为参数,开发中很常见的,block: () -> ()闭包,blockTwo: ()闭包,一般把闭包写在参数的后面
    func blockAsParam(str:String,success: () -> (),error: ()->()) -> () {

        success();
        error();
        
    }
    //有参数无返回值闭包作为参数,开发中很常见的,block: (String,Int) -> ()闭包
    func blockAsParamAndParam(successBlock: (String,Int) -> (),errorBlock: (String,Int) -> ()) -> () {
        successBlock("成功了",200);
        errorBlock("失败了",404);
    }
    
    //有参数有返回值闭包作为参数,开发中很常见的,block: (String,Int) -> ()闭包
    func blockParamAndReturn(successBlock: (String,Int)->(String),errorBlock: (String, Int)->(String)) -> () {
        
        let success = successBlock("成功了",200);
        let error = errorBlock("失败了",404);
        print(success);
        print(error);
        
    }
    
    //返回一个block闭包
    //如果单纯返回一个参数这么写 func returnBlock() -> (){}
    //如果返回一个函数参数这么写 func returnBlock() -> ()->Int{},后面的()->Int相当于一个无参带Int返回值的函数
    //其实闭包和函数的写法非常类似
    func returnBlock() -> ()->Int {

        let block = {()->Int in
            
            return 10;
            
        }
        return block;

    }
    //返回一个函数
    func returnFunc() -> ()->() {

        func blockT ()->(){
            
        }
        return blockT;

    }
    ///有一种情况当闭包作为参数,需要在函数结束后过段时间在执行,这种是逃逸闭包这个时候需要使用@escaping关键字修饰
    ///使用了这个关键字那么所有使用self的必须显示的使用self不能隐式了,就是必须把self写出来
    func blockEscaping(success: @escaping ()->()) -> () {
        
        //将success赋值给block,在合适的时机调用block,blockEscaping的回调正常执行
        block = success;
        
    }
    
    func blockEscapingTest() -> () {
        
        blockEscaping {
            print("测试逃逸");
        };
        //不执行block(),上面的block是不执行回调的
        block();
        
    }
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

闭包的值捕获
//
//  BlockViewController.swift
//  SwiftCourse
//
//  Created by 董德帅 on 2020/7/11.
//  Copyright © 2020 九天. All rights reserved.
//

import UIKit

class BlockViewController: UIViewController {

    //定义全局属性
    var globalNum = 12;
    var globalStr:String? = "全局字符串";
    static var globalStaticStr = "静态全局变量";
    
    override func viewDidLoad() {
        super.viewDidLoad()
        ///值捕获
        blockCapture();
        // Do any additional setup after loading the view.
    }
    

    ///闭包的值捕获
    func blockCapture() -> () {
        
        var num = "测试";
        let testBlock = {() -> () in
            num.append("新的字符串");
            self.globalNum = 123;
            self.globalStr = "修改全局字符串"
            BlockViewController.globalStaticStr = "修改静态全局字符串";
        }
        
        testBlock();
        //和OC不一样,局部变量可以直接被修改,不需要被修饰.全局的可以被直接修改.
        //所以在Swift中捕获的是对象不是值了.
        print(num,self.globalStr,self.globalNum,BlockViewController.globalStaticStr);
        
        //测试值的捕获.可以发现即使已经出了作用域,值还是被block一直持有,未被释放
        let blockTest = blockCaptureTest(oraginNum: 10);
        blockTest();//打印为110
        blockTest();//打印为120
        blockTest();//打印为130
        
    }
    
    ///测试值捕获
    func blockCaptureTest(oraginNum: Int) -> ()->() {
        
        var currentNum = 100;
        
        let testBlock = {()->() in
            //这里这个block捕获了currentNum和oraginNum两个值
            currentNum += oraginNum;
            print(currentNum);
        }
        //将block返回
        return testBlock;
    }
    

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

闭包的循环引用
//
//  BlockViewController.swift
//  SwiftCourse
//
//  Created by 董德帅 on 2020/7/11.
//  Copyright © 2020 九天. All rights reserved.
//

import UIKit

class BlockViewController: UIViewController {
    
    //定义全局属性
    var globalStr:String? = "全局字符串";    
  /**
    全局block,这里使用lazy的作用是确保self已经被初始化了,否则在全局的闭包中不能使用self.
    这个时候使用blockGlobal这个闭包就会引起循环引用.self强引用blockGlobal,blockGlobal强引用self
     */
     lazy var blockGlobal: () -> String = {()->(String) in
        
        //这是一个全局的block
        //在里面调用self的属性
        let n = self.globalStr ?? "22";
        return n;
        
    }
    ///解决的办法使用弱引用或者新增的一个属性无主引用,这里使用弱引用修饰
    ///将需要弱引用的使用weak修饰[weak weakSelf = self,weak delegate = self.delegate]这是个list
     lazy var blockGlobalWeak: () -> String = {[weak weakSelf = self]()->(String) in
        
        //这是一个全局的block
        //在里面调用self的属性
        if let weakS = weakSelf {
            let n = weakS.globalStr ?? "22";
            return n;
        }else{
            return "空的"
        }
        
    }
    
    ///使用无主引用
    ///将需要使用无主引用的使用unowned修饰[unowned weakSelf = self],这是个list
    lazy var blockGlobalUnowned = {[unowned self]()->String in
        
        //这是一个全局的block
        //在里面调用self的属性
            let n = self.globalStr ?? "22";
            return n;
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        ///循环引用
        blockCirculate();
        // Do any additional setup after loading the view.
    }   
    ///既然写到了闭包,那么必不可少的一件事就是循环引用,Swift同样会有
    func blockCirculate() -> () {
        
        //下面调用的这个block是会引起循环引用的
        let title = blockGlobal();
        //调用下面的两个block不会出现循环引用的问题
        let titleOne = blockGlobalWeak();
        let titleTwo = blockGlobalUnowned();
        print(title);
        
    }
    ///deinit相当于dealloc
    deinit {
        print("被释放")
    }
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

闭包相关知识更新完毕,更多精彩内容见目录本文完整代码地址

因家中有事暂停更新2020.07.15,恢复日期待定

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