Ios 为什么@noescape不能在需要时自动应用于Swift闭包?

Ios 为什么@noescape不能在需要时自动应用于Swift闭包?,ios,swift,closures,Ios,Swift,Closures,我想知道为什么标记noescape没有被自动检测到,需要显式应用它 事实上,它是在编译时检测到的,因为尝试将@noescape标记添加到带有转义闭包的func会导致错误 所以问题是为什么。。。为什么需要显式添加noescape,而Apple没有创建它以便在需要时自动添加?编辑:Swift 3在这里做了一些更改: 现在,如果需要非转义闭包,则不必将@noescape应用于将闭包作为参数的函数声明。(相反,如果确实计划在函数返回后存储闭包,则必须应用@escaping。) 闭包的“逃逸性”。因此,

我想知道为什么标记
noescape
没有被自动检测到,需要显式应用它

事实上,它是在编译时检测到的,因为尝试将@noescape标记添加到带有转义闭包的func会导致错误


所以问题是为什么。。。为什么需要显式添加noescape,而Apple没有创建它以便在需要时自动添加?

编辑:Swift 3在这里做了一些更改:

  • 现在,如果需要非转义闭包,则不必将
    @noescape
    应用于将闭包作为参数的函数声明。(相反,如果确实计划在函数返回后存储闭包,则必须应用
    @escaping
    。)
  • 闭包的“逃逸性”。因此,它不是一个看起来像
    @escaping completionHandler:(Bool,Error)->Void
    ,而是
    completionHandler:@escaping(Bool,Error)->Void
我很难重写我的整个答案来反映这一点,所以我现在就把它留在这里。。。继续阅读逃避现实背后的原因,只需记住将noescape/逃避声明倒置即可或者阅读Swift编程语言的Swift 3版本


@noescape
不仅仅是编译器优化的提示;它是函数声明呈现给调用方的接口的一部分。无论函数的参数是声明为
@noescape
还是允许转义闭包,都会改变函数调用方将闭包作为参数传递的方式

例如,给定函数(来自
SequenceType
):

如果我想根据需要在
self
上调用方法的某些条件筛选集合,我知道我可以安全地这样做,而不用担心闭包是否会捕获
self
并创建保留周期

// horribly contrived example
class Foo {
    var things: [Thing]
    func isCurrentlyAwesomeThing(thing: Thing) -> Bool { /*...*/ }
    func thingsThatAreAwesomeRightNow() -> [Thing] {
        return things.filter {
            return isCurrentlyAwesomeThing($0)
        }
    }
}
如果
filter
允许转义闭包,则调用
iscurrentlyWesomething()
的闭包将捕获
self
。(因此需要使用显式的
self.
前缀调用该方法。)如果
filter
的实现实际上将闭包保存在该函数的运行时间之外,内存泄漏是因为闭包保留了
self
,而
self
保留了
filter
函数接收闭包的数组

当您调用一个闭包参数未声明为
@noescape
的函数时,您必须考虑这种可能性。这就是为什么您会看到这样的调用:在闭包中添加一个
[weak self]
捕获列表和一个强大的重新声明,以确保
self
在闭包过程中不会被释放。(或者至少是一个
[unowned self]
,如果您合理地确定关闭不会持续超过
self


如果闭包参数不能被修饰为
@noescape
(或者由于没有该修饰符而无法转义),那么在调用接受闭包的函数时,您将不知道是否必须小心该闭包捕获的内容

编辑:Swift 3在此处进行了一些更改:

  • 现在,如果需要非转义闭包,则不必将
    @noescape
    应用于将闭包作为参数的函数声明。(相反,如果确实计划在函数返回后存储闭包,则必须应用
    @escaping
    。)
  • 闭包的“逃逸性”。因此,它不是一个看起来像
    @escaping completionHandler:(Bool,Error)->Void
    ,而是
    completionHandler:@escaping(Bool,Error)->Void
我很难重写我的整个答案来反映这一点,所以我现在就把它留在这里。。。继续阅读逃避现实背后的原因,只需记住将noescape/逃避声明倒置即可或者阅读Swift编程语言的Swift 3版本


@noescape
不仅仅是编译器优化的提示;它是函数声明呈现给调用方的接口的一部分。无论函数的参数是声明为
@noescape
还是允许转义闭包,都会改变函数调用方将闭包作为参数传递的方式

例如,给定函数(来自
SequenceType
):

如果我想根据需要在
self
上调用方法的某些条件筛选集合,我知道我可以安全地这样做,而不用担心闭包是否会捕获
self
并创建保留周期

// horribly contrived example
class Foo {
    var things: [Thing]
    func isCurrentlyAwesomeThing(thing: Thing) -> Bool { /*...*/ }
    func thingsThatAreAwesomeRightNow() -> [Thing] {
        return things.filter {
            return isCurrentlyAwesomeThing($0)
        }
    }
}
如果
filter
允许转义闭包,则调用
iscurrentlyWesomething()
的闭包将捕获
self
。(因此需要使用显式的
self.
前缀调用该方法。)如果
filter
的实现实际上将闭包保存在该函数的运行时间之外,内存泄漏是因为闭包保留了
self
,而
self
保留了
filter
函数接收闭包的数组

当您调用一个闭包参数未声明为
@noescape
的函数时,您必须考虑这种可能性。这就是为什么您会看到这样的调用:在闭包中添加一个
[weak self]
捕获列表和一个强大的重新声明,以确保
self
在闭包过程中不会被释放。(或者至少是一个
[unowned self]
,如果您合理地确定关闭不会持续超过
self

如果闭包参数不能被修饰为
@noescape
(或者由于没有该修饰符而无法转义),那么