Can't make weak reference to closure in Swift

会有一股神秘感。 提交于 2019-12-03 05:44:32

Looks like this isn't possible at the moment; you might want to file a bug.

But you can use an actual function to achieve the same thing:

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

fib(10) // 55

Computer science fun time! For a more direct translation of your code, we can use the Z combinator, with help from Swift's built-in curried function definitions:

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.)

It looks like there is no way to declare weak/unowned reference to the function; at lest for now. As workaround you can wrap your code in a class definition and have unowned reference to the instance:

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)
        }
    }
}

Usage:

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

The problem is well described here:

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

In short:

  1. Recursive closures in Swift do create strong reference cycles.
  2. There is no direct native approach in Swift to solve this problem. Capture lists don't work with closure type.
  3. Still there is a way to solve the problem: Y-combinators

You can get weak reference like this

weak var = self // Same as weak, on dealloc property will be set to nil. So var is optional

Or

unowned(unsafe) var weakSelf = self // Same as unretained

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!