我认为您问题的核心是:为什么不使用私有函数而不是丑陋的嵌套函数?
简单地说,嵌套函数可以简化可读性和封装。
同样有人会问,(函数的)局部变量与实例变量的实际用途是什么?对我来说,这确实是同一个问题。只是嵌套函数不太常见。
可读性
仍然可以从类中的其他函数访问私有函数。嵌套函数并非如此。您是在告诉您的开发人员,这仅属于此函数(与它们属于整个类的私有函数相反)。退后一步,不要乱用它,如果您需要类似的功能,请自己编写!
当你看到一个私有函数时,你必须思考,哪个函数会调用它。它是第一个函数还是最后一个函数?让我搜索一下。然而,使用嵌套函数,您不必上下查找。已经知道哪个函数会调用它。
此外,如果您有 5 个私有函数,其中 3 个在单个公共函数中调用,那么通过将它们全部嵌套在同一个公共函数下,您就可以与其他开发人员沟通这些私有函数是相关的。
简而言之,就像您不想污染公共命名空间一样,您也不想污染私有命名空间。
封装
另一个方便之处是它可以访问其父函数的所有本地参数。您不再需要传递它们。这最终意味着要测试的函数减少了,因为您已经将一个函数包装在另一个函数中。此外,如果您在非嵌套函数块中调用该函数,则不必将其包装到 self 或考虑创建泄漏。这是因为嵌套函数的生命周期与其包含函数的生命周期相关联。
另一个用例是当你的类中有非常相似的函数时,比如说你有:
extractAllHebrewNames() // right to left language
extractAllAmericanNames() // left to right language
extractAllJapaneseNames() // top to bottom language
现在,如果您有一个名为 printName 的私有函数(用于打印名称),如果您根据语言切换大小写,它会起作用,但如果您不/不能这样做怎么办。相反,您可以在每个单独的提取函数中编写自己的嵌套函数(它们现在都可以具有完全相同的名称。因为每个函数都位于不同的命名空间中。)并打印名称。
你的问题有点类似,为什么不使用“if else”而不是“switch case”。
我认为这只是提供了一种便利(对于可以在不使用嵌套函数的情况下处理的事情)。
注意:嵌套函数应该在函数中的调用点之前编写。
错误:在声明之前使用局部变量“嵌套”
func doSomething(){
nested()
func nested(){
}
}
没有错误:
func doSomething(){
func nested(){
}
nested()
}
类似地,嵌套函数中使用的局部变量必须在嵌套函数之前声明
注意:
如果您使用嵌套函数,则编译器不会强制执行 self 检查。
编译器不够聪明。它不会抛出以下错误:
Call to method 'doZ' in closure requires explicit 'self.' to make capture semantics explicit
这可能导致难以发现内存泄漏。例如
class P {
var name: String
init(name: String) {
print("p was allocated")
self.name = name
}
func weaklyNested() {
weak var _self = self
func doX() {
print("nested:", _self?.name as Any)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
doX()
}
}
func stronglyNested() {
func doZ() {
print("nested:", name)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
doZ() // will NOT throw error of: `Call to method 'doZ' in closure requires explicit 'self.' to make capture semantics explicit`
}
}
deinit {
print("class P was deinitialized")
}
}
class H {
var p: P
init(p: P) {
self.p = p
}
}
var h1: H? = H(p: P(name: "john"))
h1?.p.weaklyNested()
h1 = nil // will deallocate immediately, then print nil after 2 seconds
var h2: H? = H(p: P(name: "john"))
h2?.p.stronglyNested()
h2 = nil // will NOT deallocate immediately, will print "john" after 2 seconds, then deallocates
tl;dr 解决方案:
- 使用
weak var _self = self 并在嵌套函数引用中使用self 和weak 引用。
- 根本不要使用嵌套函数 :( 或者不要在嵌套函数中使用实例变量。
这部分是感谢Is self captured within a nested function?的原帖写的