• Swift应用案例 2.闭包入门到精通


      本文主要介绍Swift的闭包的使用并与OC的Block做比较。学习Swift是绕不过闭包的,因为无论是全局函数还是嵌套函数都是闭包的一种,本文主要介绍闭包表达式。

    1.闭包表达式的使用

            // 1.定义一个闭包
            let myClosure = {
                (s1: String, s2:String) -> Bool
                in
                self.count = 10;
                print("------");
                return s1 > s2
            }
            print(count!);
            // 2.调用闭包
            let result = myClosure("Chris","Alex")
            print("result = (result)")
            print("count = (count!)")
    

    日志

    result = true
    count = 10
    

    总结 :1.和oc的block的声明和调用在形式上是极其类似的,不过闭包可以直接修改局部变量和全局变量的值,而block需要__block 关键字。

           // 3.Tralling 闭包(尾随)
            let digitNames = [
                0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
                5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
            ]
            let numbers = [16, 58, 510]
            let strings = numbers.map {
                ( number) -> String in
                var number = number
                var output = ""
                while number > 0 {
                    output = digitNames[number % 10]! + output
                    number /= 10
                }
                return output
            }
            print(strings);
    

    日志

    ["OneSix", "FiveEight", "FiveOneZero"]
    

    2.Trailing 闭包

      函数的表现形式:(void)函数名(参数)。如果一个函数的最后一个参数是一个闭包,允许你写在参数所在哪个()外面。
    (void)函数名(参数) {
    };
    如果只有闭包一个参数,括号可以省略。变成:
    (void)函数名 {
    };
    当闭包里的代码很多的时候,这样写可以增加代码的可读性,多用于调用系统的函数。
      举例之前先介绍一下map函数,map属于Array的一个函数,调用这个函数需要传入一个闭包,返回一个新数组。Array里的每一个元素都会调用这个闭包,生成一个新对象,加入到新数组中。相当于 自动执行了for in和addobject两个方法,很实用。

    let digitNames = [
                0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
                5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
            ]
            let numbers = [16, 58, 510]
    

    使用Trailing 闭包之前

    let strings = numbers.map({
                ( number) -> String in
                var number = number
                var output = ""
                while number > 0 {
                    output = digitNames[number % 10]! + output
                    number /= 10
                }
                return output
      })
    

    使用Trailing 闭包之后

    let strings = numbers.map{
                ( number) -> String in
                var number = number
                var output = ""
                while number > 0 {
                    output = digitNames[number % 10]! + output
                    number /= 10
                }
                return output
            }
    

      就一个参数不明显, 但是参数多了还是很有用的。因为闭包里的代码一般有很多,会导致包含参数的()距离太远。

    3. 捕获: 解决嵌套函数的循环引用

    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
                
                var runningTotal = 0
                func incrementor() -> Int {
                    // 只能捕获包含他的函数体内的变量或常量的值,建立一个副本,相当于深拷贝
                    // 新变量
                    runningTotal += amount
                    return runningTotal
                }
                print(" ----- runningTotal = (runningTotal)")
                return incrementor
            }
            
            let incrementByTen = makeIncrementor(forIncrement: 10)
            print("incrementor = (incrementByTen())")
            print("incrementor = (incrementByTen())")
            print("incrementor = (incrementByTen())")
    

    打印

     ----- runningTotal = 0
    incrementor = 10
    incrementor = 20
    incrementor = 30
    

    总结:incrementor的runningTotal就是对:incrementor的runningTotal的捕获。捕获有以下几个特点。
    (1)捕获会生成一个新变量,和捕获变量的值相等,但内存不同,是引用类型,相当于OC中的深拷贝,新变量变化和捕获的变量没有任何关系了。因为incrementor的runningTotal的值一直没有改变。
    (2)嵌套函数对新变量是强引用,只要嵌套函数还在,新变量就在,因为incrementor的返回值是一直增加的。

    (3)如果不这样为什么会造成循环引用,incrementor对makeIncrementor变量runningTotal的引用就是对makeIncrementor的引用。运用捕获,就只是对runningTotal值的拷贝,不引用。

    循环引用.png

    4.闭包传值

      在OC中我们用block最多的地方就是传值了,同样闭包也是。不过运用block和闭包传值最好是当对象只有一个状态的时候,如果对象状态很多最好用代理。
    CycleScrollView 往CycleScrollViewViewController进行传值

    import UIKit
    
    // 定义闭包类型
    typealias DidSelectItemClosureType = (Int) -> Void
    class CycleScrollView: UIView, UICollectionViewDelegate,UICollectionViewDataSource {
    // Mark:UICollectionViewDelegate
        // 点击方法
        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
            
            if self.didSelectItemClosure != nil {
                // 13.利用闭包传值
                self.didSelectItemClosure!(indexPath.row == 3 ? 0 : indexPath.row);
           }
       }
    }
    

    接收闭包传过来的值

    import UIKit
    
    class CycleScrollViewViewController: UIViewController {
    
        var cycleScrollView : CycleScrollView?
        override func viewDidLoad() {
            super.viewDidLoad()
            createUI()
        }
        func createUI() {
           
            self.automaticallyAdjustsScrollViewInsets = false;
            
            cycleScrollView = CycleScrollView.init(frame: CGRect(x:0,y:64,ScreenWidth,height:ScreenHeight - 64))
            // 闭包传值
            cycleScrollView?.didSelectItemClosure =  {
                (index : Int) -> Void in
                
                print("您点击了第 (index) 个")
            }
            self.view.addSubview(cycleScrollView!)
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
    
        }
    }
    

      如果传值的例子有点没看懂,可以去下载我的DEMO,里面有详细的代码。闭包还是很厉害的,不需要我们进行任何操作就解决了循环引用问题,不像block还得对变量进行弱引用。本文部分内容是对Swift闭包详解的整理。

  • 相关阅读:
    分布式文件系统:HDFS
    MapReduce处理流程
    Maven之pom知识点
    Junit单元测试
    Mybatis中@param注解
    kafka在Maven项目中的使用
    无线/安卓安全课堂内容
    C中经常忘记的一些东西
    基于七牛API开发的前端JavaScript SDK
    常见名词解释
  • 原文地址:https://www.cnblogs.com/doujiangyoutiao/p/6626310.html
Copyright © 2020-2023  润新知