Swift3.0 闭包回调传递参数 – @escaping

非逃逸闭包:

如果一个闭包被作为一个参数传递给一个函数, 函数在return之前被立即执行,那么这个闭包是非逃逸闭包

常用的masonry或者snapkit的添加约束的方法就是非逃逸的。因为这闭包马上就执行了。

public func snp_makeConstraints(file: String = #file, line: UInt = #line, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
        ConstraintMaker.makeConstraints(view: self, file: file, line: line, closure: closure)
}

逃逸闭包:

如果一个闭包被作为一个参数传递给一个函数,并且在函数return之后才被唤起执行,那么这个闭包是逃逸闭包.并且这个闭包的参数是可以“逃出”这个函数体外的.

Swift3 中做出了一个与Swift2 对调的改变:所有的闭包都默认为非逃逸闭包,不再需要@noescape;如果是逃逸闭包,就用@escaping表示

网络请求请求结束后的回调的闭包则是逃逸的,因为发起请求后过了一段时间后这个闭包才执行

比如这个Alamofire里的处理返回json的completionHandler闭包,就是逃逸的。

public func responseJSON(
        queue queue: dispatch_queue_t? = nil,
        options: NSJSONReadingOptions = .AllowFragments,
        completionHandler: Response<AnyObject, NSError> -> Void)
        -> Self
{
        return response(
            queue: queue,
            responseSerializer: Request.JSONResponseSerializer(options: options),
            completionHandler: completionHandler
        )
}

比如下面的一段代码,callBack在函数执行完后10秒才执行,所以是逃逸闭包。

func startRequest(callBack: ()->Void ) {
    DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 10) { 
        callBack()
    }
}

=================================================

创建默认不可逃逸闭包的好处:最明显的好处就是编译器优化你的代码的性能和能力.如果编译器知道这个闭包是不可逃逸的,它可以关注内存管理的关键细节.

而且可以在不可逃逸闭包里放心的使用self关键字,因为这个闭包总是在函数return之前执行,你不需要去使用一个弱引用去引用self.

//加载请求数据
func loadData(completion: @escaping (_ result:[String]) -> ()) -> () {

    DispatchQueue.global().async {
         print("耗时操作 \(Thread.current)")

     //获取到的json结果数据
     let json = ["姓名","年龄","爱好"]

     //主队列回调
     DispatchQueue.main.async {
          print("主线程更新 UI \(Thread.current)")

           //回调异步获取的结果
           completion(json)
       }
    }
}
//调用:
//尾随闭包,
//如果函数的最后一个参数是闭包,函数参数可以提前结束,最后一个参数直接使用{},包装闭包的代码
loadData { (result) in
    print("获取结果 \(result)")
}

//按照函数本身的格式编写
loadData(completion: { (result) -> () in
    print("获取结果 \(result)")
})

Comments are closed.