在WWDC 2014的高级Swift演讲中,演讲者给出了一个使用泛型的函数回忆器的例子:
func memoize<T: Hashable, U>( body: (T)->U ) -> (T)->U {
var memo = Dictionary<T, U>()
return { x in
if let q = memo[x] { return q }
let r = body(x)
memo[x] = r
return r
}
}我很难把我的头绕在那个memo var的头上。每次对回忆录fibonacci函数的调用都包含对它的强烈引用吗?如果是这样的话,当你完成记忆的时候,你会如何释放它呢?
发布于 2014-06-20 22:16:24
在C/Objective块术语中,memo是一个__block变量(在Swift中,您不需要通过引用显式编写__block来捕获变量)。变量可以在块(闭包)中分配,所有看到该变量的作用域都会看到来自任何其他变量的更改(它们共享对变量的引用)。只要使用它的某个块(闭包)(在本例中只有一个块)仍然有效,该变量将是有效的。在最后一个使用它的块被解除分配之后,变量就超出了作用域。这是一个实现细节。
如果这个变量具有对象指针类型,那么捕获它的任何块都会保留指向的对象。但是,在这种情况下,变量是Dictionary,这是一个结构类型,它是一个值类型。因此,不需要担心内存管理。变量是结构,结构的寿命与变量一样长。(结构本身可以在其他地方分配内存,并在析构函数中释放它,但这完全是由结构在内部处理的,外部不应该知道或关心它。)
通常不需要担心__block变量如何在内部工作。但基本上,变量被包装在一个简化的“对象”类型的东西中,而实际的“变量”是这个“对象”的一个字段,它是通过引用计数来管理内存的。捕获它们的块持有对这个伪对象的“强引用”--当在使用此__block变量的堆上创建块(从技术上说,它们从堆栈块复制到堆中时)时,它会增加引用计数;当使用它的块被解除分配时,它会减少引用计数。当引用计数转到0时,这个伪“对象”将被释放,首先为其变量类型调用适当的析构函数。
要回答你的问题,“记忆斐波纳契函数”是块(闭包)。而且,这是对持有memo变量的任何内容的强烈引用。“调用”没有对它的强引用或弱引用;当调用函数时,它使用函数本身的引用。在本例中,memo变量的生存期是“记忆fibonacci函数”的生存期,因为它是捕获该变量的唯一闭包。
发布于 2014-06-20 15:12:24
每次调用memoize()都会创建自己的memo变量,独立于其他调用。只要引用它存在的闭包,它就会存在;当闭包被释放时,它捕获的变量(在本例中是memo)也会被释放。
您可以这样想,就像在这个伪代码中返回一个结构一样:
struct Closure<T,U>
{
var memo: Dictionary<T, U>
func call(t: T): U
{
....
}
}
func memoize<T: Hashable, U>( body: (T)->U ) -> Closure<T,U>
{
return Closure(memo: Dictionary<T, U>())
}发布于 2014-06-20 15:12:06
内部块(返回值)将保留备注,这意味着,只要返回的block在附近,备忘录就会持续。
每次调用memoize函数时,都会创建一个新的备忘录实例。调用返回的块将不会创建新的备忘录实例。
当返回的块超出作用域时,所有内存都将被释放。
https://stackoverflow.com/questions/24330263
复制相似问题