如何在 Swift 3(引擎盖下)中实现转义闭包?它们是否像objective-c那样隐式地block_copied/retained? [英] How are escaping closures implemented in Swift 3 (under the hood)? Are they implicitly block_copied/retained like in objective-c?

查看:14
本文介绍了如何在 Swift 3(引擎盖下)中实现转义闭包?它们是否像objective-c那样隐式地block_copied/retained?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解转义闭包在 Swift 3 中是如何工作的?来自 Objective-C 世界,对于闭包可以逃避其封闭函数的返回的场景,您必须按照以下方式做一些事情:

I am trying to understand how escaping closures work in Swift 3? Coming from the Objective-C world, for scenarios where the closure could escape the return of its enclosing function you had to do something along these lines:

@property (nonatomic, copy/strong) void (^callback)(NSData *rawData);

-(BOOL)someFunctionThatConsumesABlock:(void (^)(NSData *rawData))block 
{
  if (callback) {
      self.callback = block;
      return YES;
  }
  return NO;
}

-(void)someFunctionThatExecutesAtSomeLaterPoint
{
  NSData *data = [self bytesFromSomeProcess];
  self.callback(data);
}

基本上在objective-C中的上述代码中,消耗块的对象执行堆复制并强保留块.这种强保留是有道理的,因为块也需要在作为参数传递的函数范围之外停留(因为它是一个转义闭包/块).

Basically in the above code in objective-C, the object consuming the block performs a heap copy and strongly retains the block. This strong retaining makes sense because the block needs to stick around beyond the scope of the function it is passed as an argument too (since its an escaping closure/block).

在 Swift 3 中,似乎不再需要上述内容.所有需要做的只是将闭包注释为转义".那么 Swift 3 在幕后做了什么?它和Objective-C做同样的事情吗?从本质上讲,Swift 3 中的转义闭包是否也会被它们传递的对象隐式强保留?我不知道该语言还有什么方法可以实现这一点并使闭包保留下来".

In Swift 3, it seems the above is no longer necessary. All one needs to do is just annotate the closure as "escaping." So what is Swift 3 doing under the hood? Is it doing the same thing as objective-C? In essence do escaping closures in Swift 3 get implicitly strongly retained by the object they are being passed too? I dont see how else the language could achieve this and have the closures "stick around."

推荐答案

当您将闭包保存为属性或以其他方式保存时,确实会隐式保留(强)闭包.来自 Swift 编程语言,自动引用计数:

It is true that closures are implicitly retained (strongly) when you save them as properties or otherwise. From The Swift Programming Language, Automatic Reference Counting:

...闭包,就像类一样,是引用类型.当您为一个属性分配一个闭包时,您正在为该闭包分配一个引用.

… closures, like classes, are reference types. When you assign a closure to a property, you are assigning a reference to that closure.

(这就是捕获列表存在的原因:帮助避免意外的保留循环.)

(That's why capture lists exist: to help avoid accidental retain cycles.)

但是,我认为您可能误解了 @escaping 的目的(或者在旧版本的 Swift 中没有 @noescape).这不会不会自动为您保存闭包.相反,它只是向调用者表明您可能保存闭包(闭包可能逃避函数的执行).这允许编译器执行额外的优化,例如跳过保留.它还允许调用者在闭包中省略 self. :

However, I think you may be misunderstanding the purpose of @escaping (or the absence of @noescape in older version of Swift). This does not automatically save the closure for you. Rather, it just indicates to the caller that you might save the closure (that the closure might escape the execution of the function). This allows the compiler to perform extra optimizations, such as skipping the retain. It also allows callers to omit self. inside the closure:

class Foo {
    var x = 3

    func test() {
        [1, 2, 3].map { $0 + x }
        // `self.x` is not necessary, because the map function's
        // closure is non-escaping
    }
}

(如果您有兴趣通过 @escaping 了解幕后真正发生的事情,我不知道此类信息的权威来源,但您可能会发现一些有用的信息这篇关于 SIL 的讨论SIL.rst 开源项目中的文档,也许还有 从 WWDC16 了解 Swift 性能.)

(If you're interested in learning what's really going on under the hood with @escaping, I don't know of a definitive source for this kind of information, but you might find some useful things in this talk about SIL, the SIL.rst docs in the open-source project, and perhaps Understanding Swift Performance from WWDC16.)

这篇关于如何在 Swift 3(引擎盖下)中实现转义闭包?它们是否像objective-c那样隐式地block_copied/retained?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆