美文网首页
swift- 闭包一

swift- 闭包一

作者: Zz橙淞 | 来源:发表于2017-04-10 18:54 被阅读0次

    /*
    • 闭包表达式
    • 尾随闭包
    • 值捕获
    • 闭包是引用类型
    • 逃逸闭包
    • 自动闭包
    */

        //闭包表达式
        //闭包表达式是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单 明了。下面闭包表达式的例子通过使用几次迭代展示了 sorted(by:) 方法定义和语法优化的方式。每一次迭代 都用更简洁的方式描述了相同的功能。
        
        //sorted 方法
        //sorted(by:) 的方法,它会根据你所提供的用于排序的闭包函数将已知类型数组中的 值进行排序。一旦排序完成,sorted(by:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排 序的新数组。原数组不会被 sorted(by:) 方法修改。
       // 下面的闭包表达式示例使用 sorted(by:) 方法对一个 String 类型的数组进行字母逆序排序。以下是初始数 组:
        let names = ["Chris","Alex","Ewa","Barry","Daniella"]
        
        //sorted(by:) 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来 表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前 面,排序闭包函数需要返回 true ,反之返回 false 。
        
        func backward(_ s1:String, _ s2:String) -> Bool {
        
            return s1 > s2
        }
        var reversedNames = names.sorted(by: backward)
        
        print(reversedNames)
        
      
        //闭包的表达式语法
        // 闭包表达式语法有如下的一般形式:
    //        { (parameters) -> returnType in
    //            statements
    //        }
        
        //下面的例子展示了之前 backward(_:_:) 函数对应的闭包表达式版本的代码
        reversedNames = names.sorted(by: {
        
            (s1: String, s2: String) -> Bool in
            return s1 > s2
        })
        
        //根据上下文判断类型
        reversedNames = names.sorted(by: {
        
            s1, s2 in
            return s1>s2
        })
        
        //单表达式闭包可以通过省略 return 关键字来隐式返回单行表达式的结果
        reversedNames = names.sorted(by: {
        
            s1, s2 in s1 > s2
        })
        
      //参数名称缩写
        reversedNames = names.sorted(by: {$0 > $1})
        
        //运算符方法
        reversedNames = names.sorted(by: >)
        
        //尾随闭包
        //如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签:
        func someFunctionThatTakesAClousure(closure: () -> Void) {
        
            //函数体部分
        }
        
        
        //以下是不使用尾随闭包进行函数调用
        someFunctionThatTakesAClousure(closure: {
           //闭包主体部分
        })
        
        //以下是使用尾随闭包进行函数调用
        someFunctionThatTakesAClousure() {
            //闭包主体部分
        }
        
        
        //方法参数的字符串排序闭包可以改写为:
        reversedNames = names.sorted() {$0 > $1}
        
        //如果闭包表达式是函数或方法的唯一参数,则当你使用尾随闭包时,你甚至可以把 () 省略掉:
        reversedNames = names.sorted {$0 > $1}
        
        //当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。举例来说,Swift 的 Array 类型有一 个 map(_:) 方法,这个方法获取一个闭包表达式作为其唯一参数。该闭包函数会为数组中的每一个元素调用一 次,并返回该元素所映射的值。具体的映射方式和返回值类型由闭包来指定。
        //当提供给数组的闭包应用于每个数组元素后,map(_:) 方法将返回一个新的数组,数组中包含了与原数组中的元 素一一对应的映射后的值。
        //下例介绍了如何在 map(_:) 方法中使用尾随闭包将 Int 类型数组 [16, 58, 510] 转换为包含对应 String 类型的值的数组 ["OneSix", "FiveEight", "FiveOneZero"] :
        
        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]
        //通过传递一个尾随闭包给 numbers 数组的 map(_:) 方法来创建对应的字符串版本数组:
        let strings = numbers.map {
            (number) -> String in
            var number = number
            var output = ""
            repeat {
            
                output = digitNames[number % 10]! + output
                number /= 10
            }while number > 0
            
            return output
        }
        
        //map(_:) 为数组中每一个元素调用了一次闭包表达式。你不需要指定闭包的输入参数 number 的类型,因为可 以通过要映射的数组类型进行推断。
        
        //值捕获:闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
        func makeIncrementer(forIncrement amount: NSInteger) -> () -> NSInteger{
        
            var runningTotal = 0
            func incrementer() -> NSInteger {
            
                runningTotal += amount
                return runningTotal
            }
            return incrementer
        }
        
        
        let incrementByTen = makeIncrementer(forIncrement: 10)
        incrementByTen() // 返回的值为10 
        incrementByTen() // 返回的值为20 
        incrementByTen() // 返回的值为30
        
        let incrementBySeven = makeIncrementer(forIncrement: 7)
        incrementBySeven()// 返回的值为7
        
        //闭包是引用类型:无论你将函数或闭包赋值给一个常量还是变量,你实际上都是将常量或变量的值设置为对应函数或闭包的引用
        let alsoIncrementByTen = incrementByTen
        alsoIncrementByTen()// 返回的值为50
        print(alsoIncrementByTen())
        
        //逃逸闭包
        //当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping ,用来指明这个闭包是允许“逃逸”出这个函数的。一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。
    
        var completionHandlers: [() -> Void] = []
        func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
            completionHandlers.append(completionHandler)
        }
        //someFunctionWithEscapingClosure(_:) 函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组 中。如果你不将这个参数标记为 @escaping ,就会得到一个编译错误。
        
        //将一个闭包标记为 @escaping 意味着你必须在闭包中显式地引用 self 。比如说,在下面的代码中,传递到 s omeFunctionWithEscapingClosure(_:) 中的闭包是一个逃逸闭包,这意味着它需要显式地引用 self 。相对 的,传递到 someFunctionWithNonescapingClosure(_:) 中的闭包是一个非逃逸闭包,这意味着它可以隐式引用self 。
        func someFunctionWithNonescapingClosure(closure: () -> Void) {
            closure()
        }
        class SomeClass {
            var x = 10
            func doSomething() {
    //                someFunctionWithEscapingClosure { self.x = 100 }
    //                someFunctionWithNonescapingClosure { x = 200 }
            }
        }
        let instance = SomeClass()
        instance.doSomething()
        print(instance.x)
        // 打印出 "200"
        completionHandlers.first?()
        print(instance.x)
        // 打印出 "100"
        
        
        //自动闭包
        //自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够省略闭包的花括号,用一个普通的表达式来代替显示的闭包
        var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
        print(customersInLine.count)
        
        let customerProvider = { customersInLine.remove(at: 0) }
        print(customersInLine.count)
        print("Now serving \(customerProvider())!")
        // Prints "Now serving Chris!" print(customersInLine.count)
        // 打印出 "4"
        // customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
        func serve(customer customerProvider: () -> String) {
            print("Now serving \(customerProvider())!")
        }
        serve(customer: { customersInLine.remove(at: 0) } ) // 打印出 "Now serving Alex!"
        
       // 如果你想让一个自动闭包可以“逃逸”,则应该同时使用 @autoclosure 和 @escaping 属性。
        
        // customersInLine i= ["Barry", "Daniella"]
        var customerProviders: [() -> String] = []
        func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
            customerProviders.append(customerProvider)
        }
        collectCustomerProviders(customersInLine.remove(at: 0))
        collectCustomerProviders(customersInLine.remove(at: 0))
        print("Collected \(customerProviders.count) closures.") // 打印 "Collected 2 closures."
        for customerProvider in customerProviders {
            print("Now serving \(customerProvider())!")
        }
        // 打印 "Now serving Barry!"
        // 打印 "Now serving Daniella!"

    相关文章

      网友评论

          本文标题:swift- 闭包一

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