美文网首页
Swift 闭包

Swift 闭包

作者: kimedison | 来源:发表于2019-07-24 11:01 被阅读0次

    闭包是特殊的函数

    Swift 中,闭包其实是一个特殊的函数,匿名函数

    var block = {
        
        print("3")
    }
    
    print(block)
    

    输出

    (Function)
    

    闭包语法

    { (参数) -> 返回值类型 in
      闭包实现
      return 返回值
    }
    

    简写:

    // 单行闭包 省略 return
    let block1 = { (parm: Int) -> Int in parm + 1}
    print(block1(3))
    
    // 省略返回值类型 (单行多行闭包都可以)
    let block2 = { (parm: Int) in parm + 1}
    
    let block3 = { (parm: Int) in
        return parm + 1
    }
    print(block3(2))
    
    // 省略参数、返回值 in,直接用 $0 $1 来访问
    let block4 = {
        
        return $0 + 1
    }
    
    print(block4(5))
    
    // 如果参数的类型已知(根据函数判断),可以省略参数类型以及括号
    func tmpFunc(block: (Int) -> (Void)) {
        
        let a = 10
        
        block(a)
    }
    tmpFunc { p0 in
        print("\(p0 + 1)")
    }
    

    简写规则:

    • 如果是单行闭包,可以省略 return

    • 如果已知返回值类型(根据函数类型推断),可以省略 返回值类型

    • 如果已知参数类型,可以省略 参数类型参数的括号()

    • 如果用 $0 $1... 来访问参数,可以省略 参数int

    简单来说,除了 大括号{}函数体 之外,满足特定条件的话就都可以省略

    尾随闭包

    尾随闭包是特殊的闭包,即当在函数的最后一个参数是闭包的时候,那么这个闭包是尾随闭包

    func theFunc(parm: Int, block: (Int) -> (Void)) {
        
    }
    

    上述函数的 block 是一个尾随闭包

    特性:

    • 在调用尾随闭包的时候,可以将闭包写到参数括号外面:
    theFunc(parm: 3) { (par) -> (Void) in
        
    }
    

    这样可以增强可读性

    • 当函数只有一个闭包作为参数的时候,调用的时候可以省略 括号()
    func theFunc2(block: (Int) -> (Void)) {
        
    }
    
    theFunc2 { (par) -> (Void) in
        
    }
    

    逃逸闭包

    闭包作为参数传递给函数的时候,其作用域为函数内部,即当函数返回的时候,该闭包就释放了,如果想在函数返回之后还能执行,需要使用逃逸闭包。

    如果不显式指明闭包是逃逸闭包,则 默认是非逃逸(non-escaping) 闭包。显式指明为逃逸闭包需要在参数中增加 @escaping 关键字:

    func func0(block: @escaping () -> ()) {
    
    }
    

    函数 func0 接受的 block 是一个逃逸闭包,作用域不仅限于函数内

    通常用于需要保存闭包的场景:

    var blocks:[() -> ()] = [() -> ()]()
    
    func saveBlock(block: @escaping () -> ()) {
        
        blocks.append(block)
        
    }
    
    // 保存 block
    saveBlock {
        
        print("hello")
        
    }
    
    // 在 saveBlock 方法返回后才执行到这儿
    let block = blocks[0]
    block()
    

    输出:

    hello
    

    上述代码和输出表明,逃逸闭包的作用域不仅限于函数中。

    自动闭包

    自动闭包能将是普通闭包的一种,主要的区别的在声明的时候不需要声明参数,在调用的时候传入参数,并且由 Swift 自动将参数封装成带参数的闭包

    这一种闭包需要在闭包前加上关键字 @autoclosure,如下:

    func tmpFunc(isSuc: Bool, block:  @autoclosure ()->(Bool)) {
        
        if (isSuc) {
            block()
        }
    }
    

    该函数的 block 参数就是一个自动闭包,在传参的时候仅需要传入一个 返回值为 Bool 的表达式即可,如下:

    tmpFunc(isSuc: false, block: 2>3)
    

    思考:为什么需要自动闭包?(自动闭包的使用场景)

    主要是为了节省开销,实际上,在 tmpFunc 的声明时候,我们声明其第二个参数是一个 Bool 类型而无需是一个闭包也能很好地工作。但是假如后面的表达式需要耗费大量的时间去计算的话,且第一个参数为 false,就会造成不必要的开销,因为我们根本无需计算第二个参数的值。

    可以看出使用闭包可以省去不必要的提前计算

    func tmpFunc(isSuc: Bool, block:  @autoclosure ()->(Bool)) {
        
        if (isSuc) {
            if (block()) {
                print("a")
            }
        }
    }
    
    func tmpFunc2(isSuc: Bool, block:  Bool) {
        
        if (isSuc) {
            if (block) {
                print("b")
            }
        }
    }
    
    tmpFunc(isSuc: false, block: 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3)
    tmpFunc2(isSuc: false, block: 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3)
    

    tmpFunc 仅在 isSuctrue 的时候会调用 2>3 && 2>3 && 2>3 && 2>3 && 2>3 && 2>3 这个复杂表达式,而 tmpFunc2 无论 isSuc 为何值都会调用那个复杂的表达式,造成了不必要的复杂计算。

    相关文章

      网友评论

          本文标题:Swift 闭包

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