美文网首页
Escaping and Nonescaping Closure

Escaping and Nonescaping Closure

作者: __Guan__ | 来源:发表于2017-03-28 00:21 被阅读122次

    本文翻译自这里

    函数与闭包在Swift中作为一等公民,可以存储,当作参数传递,并且把它们看待成其他的对象或者类型。通常我们将闭包当作发送API完成后的回调。

    在Swift3中,当你将闭包当作一个函数的参数时,会有一个新的建议:编译器将闭包默认为non-escaping。下面看看non-escapingeascaping的区别。

    Non-Escaping Closures

    non-escaping的生命周期:

    1.将闭包传递给函数
    2.函数执行闭包(或不执行)
    3.函数返回

    non-escapingnon-escaping

    这个闭包并没有“逃逸(escape)”到函数体外。当函数结束时,传递的闭包离开函数作用域,并且没有其他的引用指向该闭包。

    如果考虑到内存的持有和释放平衡,这个闭包的引用计数在函数结束时和开始时是一样的。

    Escaping Closures

    现在可以猜到escaping closure是什么意思。在函数内,你可以一直运行闭包(或者不);这里有几种方法来让闭包逃逸出函数体:

    • 异步操作:如果在一个异步队列中执行闭包,那么这个队列会一直持有这个闭包。你无法确定闭包何时被执行,并且也无法保证在函数返回前结束闭包。

    • 存储:将闭包存储为全局变量、属性、或者任何其他的存储方式。

    escapingescaping

    Escaping and Non-Escaping in Swift 3

    在Swift1和2中,闭包参数默认为escaping。如果能够确保闭包没有逃逸出函数体,你可以使用@noescape修饰它。

    在Swift3中有些不同,参数闭包默认修饰为non-escaping

    如果闭包修饰为non-escaping,这里有一些潜在的优化。因为闭包不会逃逸,编译器可以将闭包的存储和调用优化。

    经常碰到的情况就是闭包中持有self的时候:

    class ClassA {
         // takes a closure (non-escaping by default) 
         func someMethod(closure: () -> Void) {  
             // secret stuff 
        }
    }
    class ClassB { 
        let classA = ClassA() 
        var someProperty = "Hello" 
        
        func testClosure() {
             classA.someMethod {
                // self is captured! 
                someProperty = "Inside the closure!" 
            } 
        }
    }
    

    当调用someMethod的时候,记住somePropertyClassB的成员属性。只有闭包为逃逸闭包的时候才必须使用self,而这段代码在Swift3中运行不会有任何问题。
    这个闭包仍然会截获self,但是因为闭包在函数结束后就会释放,所以编译器会知道没有发生循环引用。
    如果将代码改成如下这样:

    func someMethod(closure: @escaping () -> Void) {
         // secret stuff
    }
    

    现在这变成另外一种情况,当调用这个方法并且提供一个有引用指向的闭包,在闭包内必须明确使用self来提醒自己这个闭包截获了当前的self

    最后

    在Swift3中,闭包参数默认为non-escaping,根据自己的需求使用@escaping。非逃逸闭包当做参数传递时,在函数返回之前闭包必须执行完。

    相关文章

      网友评论

          本文标题:Escaping and Nonescaping Closure

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