【问题标题】:Can't make weak reference to closure in Swift不能对 Swift 中的闭包进行弱引用
【发布时间】:2014-09-03 05:50:54
【问题描述】:

更新:我试着写它而不让它变弱,而且似乎没有泄漏。所以也许这个问题不再需要了。


在 Objective-C ARC 中,当你想让一个闭包能够在闭包内部使用它自己时,块不能捕获对自身的强引用,否则它将是一个保留循环,所以你可以改为闭包捕获对自身的弱引用,如下所示:

// This is a simplified example, but there are real uses of recursive closures
int (^fib)(int);
__block __weak int (^weak_fib)(int);
weak_fib = fib = ^(int n) {
  if (n < 2)
    return n;
  else
    return weak_fib(n-1) + weak_fib(n-2);
};

我试图把它翻译成 Swift:

var fib: (Int -> Int)?
fib = { [weak fib] (n: Int) in // 'weak' cannot be applied to non-class type 'Int -> Int'
  if n < 2 {
    return n
  } else {
    return fib!(n-1) + fib!(n-2)
  }
}

但是,Swift 编译器不允许我声明要弱捕获的函数 ('weak' cannot be applied to non-class type 'Int -&gt; Int')。 [unowned fib] 也不起作用 ('unowned' cannot be applied to non-class type '(Int -&gt; Int)?')。

我知道函数不是 Swift 中的类类型。但是,它们是引用类型,并且它们确实参与了引用计数。因此,不应该有办法让它们成为弱引用或无主引用吗?

如何在没有保留循环的 Swift 中编写递归闭包?

【问题讨论】:

  • 我认为它们的意思是闭包具有引用语义(它们不只是复制自己和它们在赋值中的所有状态),而不是它们是引用计数类型。对于语言来说,递归似乎是一个足够基本的想法,他们不会犯那么大的错误......对吗?

标签: swift closures objective-c-blocks weak-references retain-cycle


【解决方案1】:

目前看来这是不可能的;你可能想file a bug。

但您可以使用实际的function 来实现相同的目的:

func fib(n: Int) -> Int {
    if n < 2 {
        return n
    } else {
        return fib(n-1) + fib(n-2)
    }
}

fib(10) // 55

计算机科学的欢乐时光!要更直接地翻译您的代码,我们可以使用the Z combinator,借助 Swift 内置的柯里化函数定义:

func Z<T, U>(f: (T -> U, T) -> U)(x: T) -> U {
    return f(Z(f), x)
}

let fib = Z { (fib: Int -> Int, n: Int) in
    if n < 2 {
        return n
    } else {
        return fib(n-1) + fib(n-2)
    }
}

fib(x: 10) // 55

// (Note the name 'x' should not be required here.
//  It seems seems to be a bug in Beta 3, since the curried function in the
//  Swift guide doesn't work as advertised either.)

【讨论】:

【解决方案2】:

看起来没有办法声明对函数的弱/无主引用;至少现在。作为解决方法,您可以将代码包装在类定义中,并让 unowned 引用实例:

class Fib {
    @lazy var calc:(Int) -> Int = {
        [unowned self] (n: Int) -> Int in
        if n < 2 {
            return n
        } else {
            return self.calc(n-1) + self.calc(n-2)
        }
    }
}

用法:

let f = Fib()
let result = f.calc(6)

【讨论】:

    【解决方案3】:

    这里已经很好地描述了这个问题:

    https://xiliangchen.wordpress.com/2014/08/04/recursive-closure-and-y-combinator-in-swift/

    简而言之:

    1. Swift 中的递归闭包确实会创建强引用循环。
    2. 在 Swift 中没有直接的本地方法来解决这个问题。捕获列表不适用于闭包类型。
    3. 还是有办法解决问题的:Y-combinators

    【讨论】:

    • “Swift 中的递归闭包确实会创建强引用循环。”不,他们没有。
    【解决方案4】:

    你可以像这样得到弱引用

    weak var = self // 同weak, on dealloc 属性将被设置为nil。所以 var 是可选的

    或者

    unowned(unsafe) var weakSelf = self // 同 unretained

    【讨论】:

      猜你喜欢
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-26
      • 1970-01-01
      • 1970-01-01
      • 2014-08-26
      相关资源
      最近更新 更多