逃逸(escaping)/非逃逸(noescape)闭包清单

本文是自己的加深理解和记忆的笔记,非原创。按照自己的理解习惯改写了其他文章的内容(引用资料在最下方),看看就好,最后强调一次,非原创。

[TOC]

1. 什么是逃逸闭包?如何标记?

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

即:作为一个传入参数,若该闭包在函数返回后才被执行的话,则该闭包就是在逃逸函数。(这样的闭包就是逃逸闭包。)你需要在参数前加上@escaping标记来表明闭包是逃逸的。

2. 什么情况下使用逃逸闭包标记?

  • 函数外存储

    如果一个函数参数可能导致引用循环,那么它需要被显示地标记出来。@escaping标记可以作为一个警告,来提醒使用这个函数的开发者注意引用关系。

    举个例子。此时的callbackself所持有,典型的可能在函数return之后被执行。

    class SomeClass {
        var callback:(()->Void)?
        func doSomething(callback:@escaping ()->Void) { // 加上逃逸修饰词
            self.callback = callback  
       }
    }
    
  • 异步调用

    同理,如果闭包被放进async dispatch queue,则该闭包也会被queue retain,同样可能在函式结束后才被执行,因此也算是“逃逸”

    举个例子。此时的callback被异步调用了

    class SomeClass {
        func doWorkAsync(block: @escaping () -> ()) { // 加上逃逸修饰词
            DispatchQueue.main.async {
                block() 
            }
        }
    }
    

3. 非逃逸闭包有什么限制

  • 不能在函式外储存

  • 不能进async dispatch queue

  • 不能作为其他逃逸闭包函数的参数

    把@noescape闭包传到其他@noescape参数是可以的,一连串不会逃逸的传值,最终还是不会逃逸(下面的@noescape会被编译器提示删除,因为swift3开始默认的就是非逃逸闭包)

    class SomeClass {
        func foo( code:@noescape (() -> String)) -> String {
            return bar(code: code)
        }
        func bar( code:@noescape (() -> String)) -> String {
            return code()
        }
    }
    

4.其他:

  • 从swift3开始,闭包默认为非逃逸闭包。之前则相反,且使用@noescape进行标记(此标记已废弃)。

  • 非逃逸闭包可用被编译器高度优化,快速的执行路径将被作为基准而使用,除非你在有需要的时候显式地使用其他方法。

  • 和弱引用关系:非逃逸闭包中可放心使用self关键字,因为不会在函数外储存,也不会被异步调用。你不需要去使用一个弱引用(weak或unowned)去引用self。

  • 在函数内部储存闭包也会被识别成逃逸,虽然并不会(现在的最新swift4仍存在这个问题)

    func doSomething(callback:(()->Void) {
        let c = callback // error: non-escaping parameter 'callback' may only be called
        c()
    }
    

引用资料:

  • 官方 Swift_Programming_Language
  • Swift @noescape與@escaping

你可能感兴趣的:(逃逸(escaping)/非逃逸(noescape)闭包清单)