美文网首页
09.Swift闭包

09.Swift闭包

作者: biyu6 | 来源:发表于2018-07-02 17:05 被阅读0次
    /*闭包:类似block代码块,可以在代码中传递和使用
        闭包的形式:
            1.全局函数:有名字,不会捕获任何值
            2.嵌套函数:有名字,能捕获其封闭函数域内值
            3.闭包表达式:没名字,可以捕获其上下文中变量或常量值
        闭包表达式语法的一般形式:
            {(参数) -> 返回类型 in
                参数不能设定默认值,可变参数(N个参数)需要放在参数列表的最后一位
                处理逻辑
            }
    
     */
    //=======================闭包表达式 - 排序示例=======================
    //闭包表达式:是一种利用 简洁语法 构建 内联闭包 的方式;示例如下:
    let names = ["Chris","Alex","Ewa","Barry","Daniella","Lily","Swift"]
    
    //调用函数的排序(参数和返回值在大括号外)
    func backward(s1: String, s2: String) -> Bool {
        return s1 > s2 //如果当前排序结束后第一个参数值出现在前面,返回true,否则返回false
    }
    var reversedNames = names.sorted(by: backward)//sorted(by:)方法接受一个闭包
    print("调用函数的降序结果:\(reversedNames)")
    
    //闭包排序1:内联闭包表达式(参数和返回值在大括号内)
    let reversedNames1 =  names.sorted(by:{ (s1: String, s2: String) -> Bool in //大括号内就是闭包的一般形式
        return s1 > s2
    })
    print("闭包一般形式排序:\(reversedNames1)")
    
    //闭包排序2:能推断出的类型都省略
    let reversedNames2 = names.sorted(by: { s1, s2 in//参数类型和返回值类型根据上下文都能推断出来,所以可以省略
        return s1 > s2
    })
    print("闭包省略类型排序:\(reversedNames2)")
    
    //闭包排序3:单表达式闭包 可以省略return关键字 隐式返回
    let reversedNames3 = names.sorted(by: {s1, s2 in
        s1 > s2
    })
    print("闭包省略返回关键字排序:\(reversedNames3)")
    
    //闭包排序4:参数名称缩写 in关键字省略
    let reversedNames4 = names.sorted {$0 > $1}
    print("闭包参数缩写的排序:\(reversedNames4)")
    
    //闭包排序5:运算符方法(极简)
    let reversedNames5 = names.sorted(by: >)
    //String类型定义了关于>的字符串实现,所以可以简单的这么干
    print("闭包运算符方法排序:\(reversedNames5)")
    
    
    //=======================尾随闭包=======================
    //尾随闭包:是一个写在函数括号之后,作为函数最后一个参数调用的闭包表达式,不需要写出闭包的参数标签
    func someFuncThatTakesAClosure(closure:() -> Void){
        print("函数体部分")
    }
    someFuncThatTakesAClosure(closure: {
        print("闭包主体部分--不使用尾随闭包进行函数调用")
    })
    someFuncThatTakesAClosure() {
        print("闭包主体部分--使用尾随闭包进行调用")
    }
    someFuncThatTakesAClosure {
        print("如果闭包表达式是函数或方法的唯一参数,在使用尾随闭包时可以省略()")
    }
    //示例:将整型数组转换成对应的字符串数组
    let numbers = [12,54,521]
    let digitNames = [0:"Zero",1:"One",2:"Two",3:"Three",4:"Four",5:"Five",6:"Six",7:"Seven",8:"Eight",9:"Nine"]
    let mapArr3 = numbers.map { (number) -> String in//不需要指定number的类型,因为可以从要映射的数组中判断出来
        var number = number//闭包或者函数的参数总是常量,所以需要一个局部变量来控制循环
        var output = ""
        repeat {
            output = digitNames[number % 10]! + output//取最后一位(字典下标返回的是一个可选值,所以需要!解包)
            number /= 10//取除最后一位外的其他几位
        }while number > 0//只要大于0就一直循环
        
        return output//闭包表达式指定的返回类型是String,指明了新的映射数组类型为字符串数组
    }
    print("map的示例3:\(mapArr3)")//["OneTwo", "FiveFour", "FiveTwoOne"]
    
    
    //=======================值捕获=======================
    /*闭包可以在其被定义的上下文中捕获常量或变量,即使定义这些常量和变量的作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值
      捕获值得闭包最简单形式是嵌套函数,嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
     */
    func makeIncrementer(forIncrement amount: Int) -> () -> Int {//传入一个amount参数,返回值是一个无参Int型返回值的函数
        var runningTotal = 0 //运行总数初始值为0
        func incrementer() -> Int{//增量计算:该函数本身无参数传入,但从外围函数捕获了runningTotal、amount变量
            runningTotal += amount
            return runningTotal
        }
        return incrementer//返回incrementer函数
    }
    let incrementByTen = makeIncrementer(forIncrement: 10)//每次增加10
    let incrementBySeven = makeIncrementer(forIncrement: 7)//每次增加7
    incrementByTen()//10
    incrementByTen()//20
    incrementByTen()//30
    incrementBySeven()//7
    incrementByTen()//40
    incrementBySeven()//14
    
    //=======================闭包是引用类型=======================
    //上面的incrementByTen 和 incrementBySeven 都是常量,但这些常量指向的闭包仍然可以增加其捕获的变量的值。这是因为函数和闭包都是引用类型。实际上可以理解为指向闭包的引用incrementBySeven 是一个常量,而并非闭包内容本身。
    //这意味着,如果将闭包赋值给两个不同的常量或变量,两个值都会指向同一个闭包:
    let alsoIncrementBySeven = incrementBySeven
    alsoIncrementBySeven()//接着上面的处理,其值为21
    
    //=======================逃逸闭包=======================
    //逃逸闭包:闭包作为参数传递到函数中,在函数返回之后该闭包才被执行,这个闭包从函数中逃逸,被称为逃逸闭包。
    //定义逃逸闭包:在函数的闭包参数名之前标注 @escaping 来表明这个闭包允许逃逸出这个函数
    
    var completionArr:[() -> Void] = [] //定义了一个数组,该数组中存储的元素是闭包
    func someFuncWithEscaping(completionHandler: @escaping () -> Void){//函数接受一个逃逸闭包作为参数,该闭包被添加到一个函数外定义的数组中
        completionArr.append(completionHandler)
    }
    func someFuncNoneEscaping(closure:() -> Void){//函数接受一个非逃逸闭包
        closure()
    }
    
    class SomeClass {//声明一个类
        var x = 10
        func doSometing(){//类中有一个方法,方法中调用了两个函数,第一个函数需要传递一个逃逸闭包的参数
            someFuncNoneEscaping {//非逃逸闭包可以隐式引用self
                x = 200
            }
            someFuncWithEscaping {//逃逸闭包需要显式引用self
                self.x = 100
            }
        }
    }
    
    let instance = SomeClass()
    instance.doSometing()
    print(instance.x)//200
    completionArr.first?()
    print(instance.x)//100
    
    //=======================自动闭包=======================
    //自动闭包是一种自动创建的闭包,用于包装 传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。
    
    //自动闭包能够延迟求值,直到调用这个闭包,闭包中的代码段才会被执行。
    var nameArr = ["张三","李四","王二","麻子","大象"]
    print(nameArr.count)//5
    
    let removeValue = {//removeValue类型不是String,而是 () -> String 一个无参,返回值为String的函数
        nameArr.remove(at: 0)//移除第0个元素,并将第0个元素赋值给removeValue
    }
    print(nameArr.count)//5,上面的函数没有被调用,所以数组没有发生移除事件,元素个数还是5
    print("移除的人叫:\(removeValue())")//执行闭包
    print(nameArr.count)//4,上一句调用了移除函数,数组元素变成了4
    
    //闭包作为参数传递给函数
    func serve(customer customerProvider: () -> String){//一个函数接收一个闭包作为参数
        print("现在的值:\(customerProvider())")//打印其值
    }
    serve(customer: {nameArr.remove(at: 0)})//调用函数,并将闭包表达式作为参数传递到函数中,打印结果:现在的值:李四
    
    //逃逸的自动闭包: 同时使用@autoclosure 和 @escaping 属性
    var nameValueArr = ["轰天","战绩","潜艇","航母","飞机"]
    var taoYiArr: [() -> String] = [] //元素为闭包的数组
    func chuli(_ prams: @autoclosure @escaping () -> String){//逃逸的自动闭包,没有调用传入的prams闭包
        taoYiArr.append(prams)//给数组添加元素,而是将闭包追加到taoYiArr中,在函数返回后才被调用
    }
    
    chuli(nameValueArr.remove(at: 0))//移除:轰天,调用函数,将表达式的值作为闭包传入到函数中
    chuli(nameValueArr.remove(at: 0))//移除:战绩,调用函数,将表达式的值作为闭包传入到函数中
    print(taoYiArr.count)//2,轰天、战绩
    
    for taoYi in taoYiArr {
        print(taoYi())//轰天、战绩
    }
    
    

    相关文章

      网友评论

          本文标题:09.Swift闭包

          本文链接:https://www.haomeiwen.com/subject/fimluftx.html