美文网首页
Swift3:@escaping

Swift3:@escaping

作者: keenteam | 来源:发表于2017-09-18 13:34 被阅读30次

@escaping

在Swift3中,闭包默认是非逃逸的。在Swift3之前,事情是完全相反的:那时候逃逸闭包是默认的,对于非逃逸闭包,你需要标记@noescaping。Swift3的行为更好。因为它默认是安全的:如果一个函数参数可能导致引用循环,那么它需要被显示地标记出来。@escaping标记可以作为一个警告,来提醒使用这个函数的开发者注意引用关系。非逃逸闭包可用被编译器高度优化,快速的执行路径将被作为基准而使用,除非你在有需要的时候显式地使用其他方法。

@escaping标明这个闭包是会“逃逸”,通俗点说就是这个闭包在函数执行完成之后才被调用。为了体现@escaping的作用,我们在之前先做一个铺垫:

func doWork(block:()->()) {

print("header")

block()

print("footer")

}

doWork {

print("work")

}

//控制台打印的消息如下:

//header

//work

//footer

对于上述的block调用是同步行为。我们修改一下代码,将block放到一个异步操作中,让它在doWork返回后被调用。这个时候我们就需要用@escaping标记表明这个闭包是会“逃逸”的。

func doWorkAsync(block: @escaping () -> ()) {

DispatchQueue.main.async {

block()

}

}没有逃逸的闭包的作用域是不会超过函数本身的,所以说我们不需要担心在闭包内持有self。逃逸的闭包就不同了,因为需要确保闭包内的成员依然有效,如果在闭包内引用self以及self的成员的话,就要考虑闭包内持有self的情况了。

class S {

var foo = "foo"

func method1() {

doWork {

print(foo)

}

foo = "bar"

}

func method2() {

doWorkAsync {

print(self.foo)

}

foo = "bar"

}

func method3() {

doWorkAsync {

[weak self] _ in

print(self?.foo)

}

foo = "bar"

}

}

S().method1()// foo

S().method2()// bar

S().method3()// nil

method1不需要考虑self .foo的持有情况,而method2需要考虑,我们让闭包持有了self,打印的值就是foo赋值之后的内容bar,如果我们不希望闭包内持有self的话,可以使用[weak self]的方法来表示. method3就是这样,在闭包执行的时候已经没有了对实例对象的引用,所有说输出是nil。

weak 和 unowned

上面我用的是 [weak self] ,如果用[unowned self]表示的话,method3就需要稍做修改:

func method3() {

doWorkAsync {

[unowned self] _ in

print(self.foo)

}

foo = "bar"

}

这两者都是用来防止循环引用的,但是还是有一点小小的区别:unowned 有点像oc里面的unsafe_unretained,而weak就是以前的weak。对于这两者的使用,不能说用哪一个要好一点,要视情况而定。用unowned的话,即使它原来的引用的内容被释放了,它仍然会保持对被已经释放了的对象的一个引用,它不能是Optional也不能是nil值,这个时候就会出现一个问题,如果你调用这个引用方法或者访问成员属性的话,就会出现崩溃。而weak要稍微友善一点,在引用的内容被释放之后,会自动将weak的成员标记为nil。有人要说,既然这样,那我全部使用weak。但是在可能的情况下,我们还是应该倾向于尽量减少出现Optional 的可能性,这样有助于代码的简化。Apple给我们的建议是如果能够确定访问时不会被释放的话,尽量用unowned,如果存在被释放的可能性的话,就用weak。

在Playground里面进行异步操作

上面的代码如果你在Playground里面运行的话,你会发现method2,method3方法里面的回调不会走。不会走的原因大概是来不及走,三个函数一执行完,程序就终止了,异步来不及执行。怎么来解决这个问题呢?在Xcode 8 里面我们可以import PlaygroundSupport,在调用方法前设置PlaygroundPage.current.needsIndefiniteExecution = true就好了。

PlaygroundPage.current.needsIndefiniteExecution = true

S().method1()// foo

S().method2()// bar

S().method3()// nil

相关文章

  • swift 3.0 之@Never | @escaping

    @escaping Swift3,闭包参数默认为non-escaping,也可以使用@escaping属性关键字为...

  • Swift3:@escaping

    @escaping 在Swift3中,闭包默认是非逃逸的。在Swift3之前,事情是完全相反的:那时候逃逸闭包是默...

  • Swift3:@escaping

    @escaping 在Swift3中,闭包默认是非逃逸的。在Swift3之前,事情是完全相反的:那时候逃逸闭包是默...

  • swift : Escaping closure capture

    Escaping closure captures non-escaping parameter 'complet...

  • Swift 3.0 @escaping与@non-escapin

    @escaping与@non-escaping声明用来修饰闭包的 @escaping:闭包的生命周期不在传入的函数...

  • @escaping

    定义:如果一个闭包在一个函数return之后才被调用那么这个闭包就escaping了 swift 2 默认esca...

  • swift:Closure 闭包

    @noescape @autoclosure @autoclosure(escaping)

  • Dream of Escaping

    Dream of Escaping Figure: Laila, Rasheed, Tariq ...

  • swift3-generics

    swift3

  • 注解

    官方网站 @escaping * 修饰 block

网友评论

      本文标题:Swift3:@escaping

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