13

更新:我尝试在不使其变弱的情况下编写它,并且似乎没有泄漏。所以也许这个问题不再需要了。


在 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 -> Int')。[unowned fib]也不起作用('unowned' cannot be applied to non-class type '(Int -> Int)?')。

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

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

4

4 回答 4

6

目前看来这是不可能的;你可能想提交一个错误

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

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

fib(10) // 55

计算机科学有趣的时间!为了更直接地翻译您的代码,我们可以使用Z 组合器,借助 Swift 的内置 curried 函数定义:

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.)
于 2014-07-13T05:48:17.013 回答
1

看起来没有办法声明对函数的弱/无主引用;至少现在。作为解决方法,您可以将代码包装在类定义中并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)
于 2014-07-13T07:53:07.220 回答
1

问题在这里得到了很好的描述:

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

简而言之:

  1. Swift 中的递归闭包确实会创建强引用循环。
  2. Swift 中没有直接的原生方法来解决这个问题。捕获列表不适用于闭包类型。
  3. 仍然有解决问题的方法:Y-combinators
于 2015-08-07T12:52:29.103 回答
-1

你可以像这样得到弱参考

weak var = self // 和weak一样,dealloc属性会被设置为nil。所以 var 是可选的

或者

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

于 2014-12-09T08:38:07.783 回答