Reputation: 178
I met a similar question in Swift Memory Management: Storing func in var but that didn't solve my problem.
Here is my class definition:
class Test {
var block: (() -> Int)?
func returnInt() -> Int {
return 1
}
deinit {
print("Test deinit")
}
}
I tried two ways to assign value to block
property and got completely different result. The second approach didn't cause retain circle, which is quite unexpected:
var t = Test()
// This will lead to retain cycle
// t.block = t.returnInt
// I thought this will also lead to retain cycle but actually didn't
t.block = {
return t.returnInt()
}
t = Test()
In my opinion, variable t
is captured by block
while block
is a property of t
, so can anyone explain why there isn't a retain cycle?
Upvotes: 4
Views: 679
Reputation: 122449
In Swift, all captured variables are captured by reference (in Apple Blocks terminology, all captured local variables are __block
). So the t
inside the block is shared with the t
outside the block; the block does not hold an independent copy of t
.
Originally, there is a retain cycle in the second case too, as the block holds a reference to this shared copy of t
, and t
points to the first Test
object, and that Test
object's block
property points to the block. However, when you re-assign the shared variable t
(which is visible both inside and outside the block), you break the retain cycle, because t
no longer points to the first Test
object.
In the first case, the t
is effectively captured by value, because the t
is evaluated immediately in the expression t.returnInt
rather than be captured as a variable in a block. So a reassignment of t
outside the block later has no effect on the block, and does not break the retain cycle. So you can think of
t.block = t.returnInt
as kind of like
let tmp = t
t.block = {
return tmp.returnInt()
}
Upvotes: 2