首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swift闭包中保留内存的生存期

Swift闭包中保留内存的生存期
EN

Stack Overflow用户
提问于 2014-06-20 15:02:11
回答 3查看 3.9K关注 0票数 8

在WWDC 2014的高级Swift演讲中,演讲者给出了一个使用泛型的函数回忆器的例子:

代码语言:javascript
复制
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函数的调用都包含对它的强烈引用吗?如果是这样的话,当你完成记忆的时候,你会如何释放它呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-06-20 22:16:24

在C/Objective块术语中,memo是一个__block变量(在Swift中,您不需要通过引用显式编写__block来捕获变量)。变量可以在块(闭包)中分配,所有看到该变量的作用域都会看到来自任何其他变量的更改(它们共享对变量的引用)。只要使用它的某个块(闭包)(在本例中只有一个块)仍然有效,该变量将是有效的。在最后一个使用它的块被解除分配之后,变量就超出了作用域。这是一个实现细节。

如果这个变量具有对象指针类型,那么捕获它的任何块都会保留指向的对象。但是,在这种情况下,变量是Dictionary,这是一个结构类型,它是一个值类型。因此,不需要担心内存管理。变量是结构,结构的寿命与变量一样长。(结构本身可以在其他地方分配内存,并在析构函数中释放它,但这完全是由结构在内部处理的,外部不应该知道或关心它。)

通常不需要担心__block变量如何在内部工作。但基本上,变量被包装在一个简化的“对象”类型的东西中,而实际的“变量”是这个“对象”的一个字段,它是通过引用计数来管理内存的。捕获它们的块持有对这个伪对象的“强引用”--当在使用此__block变量的堆上创建块(从技术上说,它们从堆栈块复制到堆中时)时,它会增加引用计数;当使用它的块被解除分配时,它会减少引用计数。当引用计数转到0时,这个伪“对象”将被释放,首先为其变量类型调用适当的析构函数。

要回答你的问题,“记忆斐波纳契函数”是块(闭包)。而且,这是对持有memo变量的任何内容的强烈引用。“调用”没有对它的强引用或弱引用;当调用函数时,它使用函数本身的引用。在本例中,memo变量的生存期是“记忆fibonacci函数”的生存期,因为它是捕获该变量的唯一闭包。

票数 12
EN

Stack Overflow用户

发布于 2014-06-20 15:12:24

每次调用memoize()都会创建自己的memo变量,独立于其他调用。只要引用它存在的闭包,它就会存在;当闭包被释放时,它捕获的变量(在本例中是memo)也会被释放。

您可以这样想,就像在这个伪代码中返回一个结构一样:

代码语言:javascript
复制
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>())
}
票数 3
EN

Stack Overflow用户

发布于 2014-06-20 15:12:06

内部块(返回值)将保留备注,这意味着,只要返回的block在附近,备忘录就会持续。

每次调用memoize函数时,都会创建一个新的备忘录实例。调用返回的块将不会创建新的备忘录实例。

当返回的块超出作用域时,所有内存都将被释放。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24330263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档