AyB*_*Bay 5 closures objective-c objective-c-blocks swift swift3
我想了解转义闭包在 Swift 3 中是如何工作的?来自 Objective-C 世界,对于闭包可以逃避其封闭函数的返回的场景,您必须按照以下方式做一些事情:
@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);
}
Run Code Online (Sandbox Code Playgroud)
基本上在objective-C的上述代码中,消耗块的对象执行堆复制并强保留块。这种强保留是有道理的,因为块也需要在它作为参数传递的函数范围之外停留(因为它是一个转义闭包/块)。
在 Swift 3 中,似乎不再需要上述内容。所有需要做的只是将闭包注释为“转义”。那么 Swift 3 在幕后做了什么?它和Objective-C做同样的事情吗?从本质上讲,Swift 3 中的转义闭包是否也会被它们传递的对象隐式强保留?我不知道该语言还有什么方法可以实现这一点并使闭包“保持不变”。
当您将闭包保存为属性或其他方式时,闭包确实会被隐式保留(强保留)。来自 Swift 编程语言,自动引用计数:
\n\n\n\n\n\xe2\x80\xa6 闭包与类一样,都是引用类型。当您将闭包分配给属性时,您正在分配对该闭包的引用。
\n
(这就是捕获列表存在的原因:帮助避免意外的保留周期。)
\n\n但是,我认为您可能误解了(或旧版本 Swift 中@escaping缺少)的目的。@noescape这不会自动为您保存关闭。相反,它只是向调用者表明您可以保存闭包(闭包可能会逃脱函数的执行)。这允许编译器执行额外的优化,例如跳过保留。它还允许调用者self.在闭包内省略:
class Foo {\n var x = 3\n\n func test() {\n [1, 2, 3].map { $0 + x }\n // `self.x` is not necessary, because the map function\'s\n // closure is non-escaping\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n(如果您有兴趣了解 的幕后情况@escaping,我不知道此类信息的明确来源,但您可能会在有关 SIL 的演讲中找到一些有用的内容,开源项目中的SIL.rst文档,也许还有 WWDC16 中的Understanding Swift Performance。)