Strong reference cycle in a closure

I've thought whole day but don't get it: why the following code doesn't cause strong reference cycle?


class C {
  var m: () -> () = {}

  init?() { println("init") }
  deinit { println("deinit") }
}

var ci = C()

ci?.m = { println(ci) }

ci = nil


In fact, ci has a strong reference to m which has a strong reference to ci.. but the output is:

> init
> deinit
Answered by LCS in 8240022

If you add a bit of code and run it in a playground (Xcode 7 beta):


class C
{
    var m: () -> () = {}
    let identity: String
   
    init?(_ name: String)
    {
        identity = name
        print("init \(identity)")
    }
    deinit
    {
        self.m()
        print("deinit \(identity)")
    }
}


var ci = C("a")

ci!.m =
{
    var text = "reference = \(ci!.identity)"
    print(text)
}

ci = C("b")


when ci.m is run in deinit, it actually prints out "reference = b" even though it is deallocating a.


The closure is actually capturing a reference to the local variable c1, not a reference to the instance that c1 is pointing to at the time. So no strong reference cycle is created.

Accepted Answer

If you add a bit of code and run it in a playground (Xcode 7 beta):


class C
{
    var m: () -> () = {}
    let identity: String
   
    init?(_ name: String)
    {
        identity = name
        print("init \(identity)")
    }
    deinit
    {
        self.m()
        print("deinit \(identity)")
    }
}


var ci = C("a")

ci!.m =
{
    var text = "reference = \(ci!.identity)"
    print(text)
}

ci = C("b")


when ci.m is run in deinit, it actually prints out "reference = b" even though it is deallocating a.


The closure is actually capturing a reference to the local variable c1, not a reference to the instance that c1 is pointing to at the time. So no strong reference cycle is created.

Now I understand, thanks!

Of course that is strong reference cycle, until

ci = nil


If you do not want to write the code above and want to prevent strong reference cycle, use weak/unowned or capture list.

method 1

var ci = C()
weak var weakC = ci
Ci?.m = {
     println(weakC!)
}

method 2

r ci = C()
Ci?.m = {
     [unwoned ci = ci!] in
     println(ci)
}
Strong reference cycle in a closure
 
 
Q