Swift5.2连载

Swift闭包(7)

2020-07-12  本文已影响0人  _菩提本无树_

教程目录
与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.
    }
    */

}

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

上一篇下一篇

猜你喜欢

热点阅读