Why does adding a closure capture list prevent my instance from being deallocated? - swift

class Name {
var name: String
init(name: String) {
self.name = name
}
deinit {
print("\(name) deinit")
}
}
var x: Name? = Name(name: "abc")
var someClosure = {
print("\(x?.name)")
}
someClosure()
x = nil
And then the console will output:
Optional("abc")
abc deinit
It can be seen that the "deinit" function was called. So it does not form a strong reference cycle.
But if I add a capture list to the closure:
var someClosure = { [x] in
print("\(x?.name)")
}
The console will output:
Optional("abc")
And the "deinit" function was not called. So the object and reference form a strong reference cycle.
What is the reason? What's the difference between these two conditions?

First of all, there's no strong retain cycle in either case – you just simply have a global closure variable that's holding a strong reference to your class instance, therefore preventing it from being deallocated.
In your first example, when you capture x in the closure:
var someClosure = {
print("\(x?.name)")
}
What you've got (in effect) is a reference to a reference – that is, the closure has a reference to the storage of x, which then has a reference to your class instance. When you set x to nil – the closure still has a reference to the storage of x, but now x doesn't have a reference to your class instance. Thus, your class instance no longer has any strong references to it, and can be deallocated.
In your second example when you use a capture list:
var someClosure = { [x] in
print("\(x?.name)")
}
You're copying x itself – that is, you're copying a reference to the instance of your class. Therefore the closure will keep your class retained as long as it exists. Setting x to nil doesn't affect the closure's reference to your instance, as it has it's own strong reference to it.

This is what I think happens here.
ARC adds a reference count to x when x is created. When the closure is called with a capture list, it then adds another count (closure captures the object: thus indicating to the compiler it will need x in the future, by increasing the reference count). So x now has ARC count of 2.
When you assign x to nil it reduces the reference count by 1. If the count is 0, or there are only weak references to the object, then the object is deinitialized. If the count is more than 0, and the references are strong, the object is retained.
Without explicitly passing the capture list to the closure it only weakly captures the object. ARC then decides it is safe to deinit the object once the closure is done with it. Passing the capture list indicates to ARC that the object might be needed for the closure to operate on at various multiple times, so a strong reference is made.
Put another call to someClosure() after x = nil and see what happens in both cases.

Related

What's the difference between these two declarations of delegates?

I'm learning about delegates and I don't understand why
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
let friendsFunctions = FriendsFunctions()
friendsFunctionsDelegate.delegate = friendsFunctions
is correct whilst
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
friendsFunctionsDelegate.delegate = FriendsFunction()
is wrong.
Here is the full code:
protocol FriendsDelegate: AnyObject {
func orderPizza()
func takeABreak()
}
class FriendsFunctionsDelegate {
weak var delegate: FriendsDelegate? = nil
func buyPizza() {
delegate?.orderPizza()
}
func sleep() {
delegate?.takeABreak()
}
}
class FriendsFunctions: FriendsDelegate {
func orderPizza() {
print("I ordered a pizza")
}
func takeABreak() {
print("I'm going to sleep")
}
}
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
let friendsFunctions = FriendsFunctions()
friendsFunctionsDelegate.delegate = friendsFunctions
ARC (for Automatic Reference Counting)
ARC is the system which manages automatically the memory allocation / deallocation for your objects.
The way it works is that as long as you'll have AT LEAST 1 strong reference to an object in your code it will remain in memory. Please note that by default any property definition not define as weak is implicitly strong.
When specifying a property as weak it won't increment the "holding reference count" by one.
The issue you are experiencing...
In your first example, when you first create a let constant you hold a strong reference to it, then you assign it to the weak variable.
You have then =>
1 weak reference to the object (stored on the friendsFunctionsDelegate.delegate)
1 strong reference to the object (the let constant let friendsFunctions = FriendsFunctions())
As a result, ARC is NOT deallocating the object (strong reference >= 1) => It is working ✅
In your second example, when you directly instantiate + assign the delegate to the weak variable WITHOUT creating a constant first.
You have then =>
1 weak reference to the object (stored on the friendsFunctionsDelegate.delegate)
0 strong reference to the object
As a result, ARC is deallocating (release from memory) the object (strong reference == 0) directly after the assignment => Not working ❌
Conclusion
As a conclusion, you need to keep a strong reference somewhere to that delegate object.
Weak usage in delegate pattern
When using delegation we use a weak property to prevent memory retain cycle. This is happening when you have one object (Object A) holding a strong reference to another object (Object B) which is also having a strong reference to the first object (Object A).
A => B STRONG
B => A STRONG
=> ⚠️RETAIN CYCLE⚠️
When you'll try to get rid of object A or B from memory strong reference count will still be 1, you'll then get a memory leak with memory filled with unused objects, which might lead to an usable app. The solution is to define one of those 2 references as weak (not both). When applying the delegate pattern, you would define the property holding the reference to the delegate as weak.
Few extra comments:
Be careful to the naming which might be misleading. The delegate keyword should be appended only to the protocol and not to the class name. If you remove it though you would have an overlap, which is a hint that the naming could have more appropriately defined.
When you define a property as Optional and you want it to be nil as default, you don't have to explicitly specify the = nil. Though you can still do it ;)
Best practices tell you that when you want a class to conform to a delegate / protocol, you should go with an extension instead of directly conforming at the class definition.
Delegate pattern should be a blind communication pattern, so your class should not be aware about out of scope functions. Then the naming of the delegate methods should be modified to something like func didBuyPizza() and func didTakeABreak()or similar.
The one with
let friendsFunctions = FriendsFunctions() // holds a strong reference
friendsFunctionsDelegate.delegate = friendsFunctions
Works as it holds a strong reference , while this
friendsFunctionsDelegate.delegate = FriendsFunction()
Don't work as both parts (lhs & rhs) are weak so no retaining happens ( delegate is a weak property )
Notice how the FriendsFunctionsDelegate.delegate property is a weak reference:
weak var delegate: FriendsDelegate? = nil
^^^^
If you did
friendsFunctionsDelegate.delegate = FriendsFunction()
You created a FriendsFunction object, and the only object that has a reference to it is friendsFunctionsDelegate, via its delegate property. But this is a weak reference. There is no strong reference to the new FriendsFunction object! As a result, it will be deallocated immediately after it is created.
You should see a warning here that says:
Instance will be immediately deallocated because property 'delegate' is 'weak'
On the other hand, if you put the newly created FriendsFunction object into a let constant first,
let friendsFunctions = FriendsFunctions()
That let constant, friendsFunctions will be a strong reference to the FriendsFunctions object, since it is not weak. And since there is at least one strong reference to it, the object will not be deallocated until all the strong references are gone.
For more info, see Automatic Reference Counting in the Swift guide.

How can I Intentionally create a Zombie Object in Swift [duplicate]

I've read How to demonstrate memory leak and zombie objects in Xcode Instruments? but that's for objective-c. The steps don't apply.
From reading here I've understood zombies are objects which are:
deallocated
but something pointer is still trying to point to them and send messages to them.
not exactly sure how that's different from accessing a deallocated object.
I mean in Swift you can do:
var person : Person? = Person(name: "John")
person = nil
print(person!.name)
Is person deallocated? Yes!
Are we trying to point to it? Yes!
So can someone share the most common mistake which leads to creating a dangling pointer?
Here's zombie attack in under 15 lines of code:
class Parent { }
class Child {
unowned var parent: Parent // every child needs a parent
init(parent: Parent) {
self.parent = parent
}
}
var parent: Parent? = Parent()
let child = Child(parent: parent!) // let's pretend the forced unwrap didn't happen
parent = nil // let's deallocate this bad parent
print(child.parent) // BOOM!!!, crash
What happens in this code is that Child holds an unowned reference to Parent, which becomes invalid once Parent gets deallocated. The reference holds a pointer to the no longer living parent (RIP), and accessing that causes a crash with a message similar to this:
Fatal error: Attempted to read an unowned reference but object 0x1018362d0 was already deallocated2018-10-29 20:18:39.423114+0200 MyApp[35825:611433] Fatal error: Attempted to read an unowned reference but object 0x1018362d0 was already deallocated
Note The code won't work in a Playground, you need a regular app for this.
This is not a dangling pointer or a zombie. When you use ! you're saying "if this is nil, then crash." You should not think of person as a pointer in Swift. It's a value. That value may be .some(T) or it may be .none (also called nil). Neither of those is dangling. They're just two different explicit values. Swift's nil is nothing like null pointers in other languages. It only crashes like null pointers when you explicitly ask it to.
To create zombies, you'll need to be using something like Unmanaged. This is extremely uncommon in Swift.
Zombie objects are Objective-C objects which have been deallocated, but still receive messages.
In Objective-C, __unsafe_unretained can be used to create an additional pointer to an object which does not increase the reference count. In Swift that would be unowned(unsafe).
Here is a self-contained example:
import Foundation
class MyClass: NSObject {
func foo() { print("foo"); }
deinit { print("deinit") }
}
unowned(unsafe) let obj2: MyClass
do {
let obj1 = MyClass()
obj2 = obj1
print("exit scope")
}
obj2.foo()
obj1 is a pointer to a newly created object, and obj2 is another pointer to the same object, but without increasing the reference counter. When the do { ... } block is left, the object is deallocated. Sending a message to it via obj2 causes the Zombie error:
exit scope
deinit
*** -[ZombieTest.MyClass retain]: message sent to deallocated instance 0x1005748d0
This can also happen if you use Managed (e.g. to convert pointers to Swift objects to C void pointers in order to pass them to C callback functions) and you don't choose the correct retained/unretained combination. A contrived example is:
let obj2: MyClass
do {
let obj1 = MyClass()
obj2 = Unmanaged.passUnretained(obj1).takeRetainedValue()
print("exit scope")
}
obj2.foo()
Zombie Object is a deallocated object which behaves itself like alive. It is possible because of dangling pointer.
dangling pointer points on some address in the memory where data is unpredictable
Objective-C has unsafe_unretained[About] property attributes. [Example]
Swift has
unowned(unsafe)[About] reference
Unmanaged - a wrapper for non ARC Objc- code
unowned(unsafe) let unsafeA: A
func main() {
let a = A() // A(ref count = 1)
unsafeA = a
} // A(ref count = 0), deinit() is called
func additional() {
unsafeA.foo() //<- unexpected
}

Struct cannot have a stored property that references itself [duplicate]

Reference cycles in Swift occur when properties of reference types have strong ownership of each other (or with closures).
Is there, however, a possibility of having reference cycles with value types only?
I tried this in playground without succes (Error: Recursive value type 'A' is not allowed).
struct A {
var otherA: A? = nil
init() {
otherA = A()
}
}
A reference cycle (or retain cycle) is so named because it indicates a cycle in the object graph:
Each arrow indicates one object retaining another (a strong reference). Unless the cycle is broken, the memory for these objects will never be freed.
When capturing and storing value types (structs and enums), there is no such thing as a reference. Values are copied, rather than referenced, although values can hold references to objects.
In other words, values can have outgoing arrows in the object graph, but no incoming arrows. That means they can't participate in a cycle.
As the compiler told you, what you're trying to do is illegal. Exactly because this is a value type, there's no coherent, efficient way to implement what you're describing. If a type needs to refer to itself (e.g., it has a property that is of the same type as itself), use a class, not a struct.
Alternatively, you can use an enum, but only in a special, limited way: an enum case's associated value can be an instance of that enum, provided the case (or the entire enum) is marked indirect:
enum Node {
case None(Int)
indirect case left(Int, Node)
indirect case right(Int, Node)
indirect case both(Int, Node, Node)
}
Disclaimer: I'm making an (hopefully educated) guess about the inner workings of the Swift compiler here, so apply grains of salt.
Aside from value semantics, ask yourself: Why do we have structs? What is the advantage?
One advantage is that we can (read: want to) store them on the stack (resp. in an object frame), i.e. just like primitive values in other languages. In particular, we don't want to allocate dedicated space on the heap to point to. That makes accessing struct values more efficient: we (read: the compiler) always knows where exactly in memory it finds the value, relative to the current frame or object pointer.
In order for that to work out for the compiler, it needs to know how much space to reserve for a given struct value when determining the structure of the stack or object frame. As long as struct values are trees of fixed size (disregarding outgoing references to objects; they point to the heap are not of interest for us), that is fine: the compiler can just add up all the sizes it finds.
If you had a recursive struct, this fails: you can implement lists or binary trees in this way. The compiler can not figure out statically how to store such values in memory, so we have to forbid them.
Nota bene: The same reasoning explains why structs are pass-by-value: we need them to physically be at their new context.
Quick and easy hack workaround: just embed it in an array.
struct A {
var otherA: [A]? = nil
init() {
otherA = [A()]
}
}
You normally cannot have a reference cycle with value types simply because Swift normally doesn't allow references to value types. Everything is copied.
However, if you're curious, you actually can induce a value-type reference cycle by capturing self in a closure.
The following is an example. Note that the MyObject class is present merely to illustrate the leak.
class MyObject {
static var objCount = 0
init() {
MyObject.objCount += 1
print("Alloc \(MyObject.objCount)")
}
deinit {
print("Dealloc \(MyObject.objCount)")
MyObject.objCount -= 1
}
}
struct MyValueType {
var closure: (() -> ())?
var obj = MyObject()
init(leakMe: Bool) {
if leakMe {
closure = { print("\(self)") }
}
}
}
func test(leakMe leakMe: Bool) {
print("Creating value type. Leak:\(leakMe)")
let _ = MyValueType(leakMe: leakMe)
}
test(leakMe: true)
test(leakMe: false)
Output:
Creating value type. Leak:true
Alloc 1
Creating value type. Leak:false
Alloc 2
Dealloc 2
Is there, however, a possibility of having reference cycles with value types only?
Depends on what you mean with "value types only".
If you mean completely no reference including hidden ones inside, then the answer is NO. To make a reference cycle, you need at least one reference.
But in Swift, Array, String or some other types are value types, which may contain references inside their instances. If your "value types" includes such types, the answer is YES.

Reference cycles with value types?

Reference cycles in Swift occur when properties of reference types have strong ownership of each other (or with closures).
Is there, however, a possibility of having reference cycles with value types only?
I tried this in playground without succes (Error: Recursive value type 'A' is not allowed).
struct A {
var otherA: A? = nil
init() {
otherA = A()
}
}
A reference cycle (or retain cycle) is so named because it indicates a cycle in the object graph:
Each arrow indicates one object retaining another (a strong reference). Unless the cycle is broken, the memory for these objects will never be freed.
When capturing and storing value types (structs and enums), there is no such thing as a reference. Values are copied, rather than referenced, although values can hold references to objects.
In other words, values can have outgoing arrows in the object graph, but no incoming arrows. That means they can't participate in a cycle.
As the compiler told you, what you're trying to do is illegal. Exactly because this is a value type, there's no coherent, efficient way to implement what you're describing. If a type needs to refer to itself (e.g., it has a property that is of the same type as itself), use a class, not a struct.
Alternatively, you can use an enum, but only in a special, limited way: an enum case's associated value can be an instance of that enum, provided the case (or the entire enum) is marked indirect:
enum Node {
case None(Int)
indirect case left(Int, Node)
indirect case right(Int, Node)
indirect case both(Int, Node, Node)
}
Disclaimer: I'm making an (hopefully educated) guess about the inner workings of the Swift compiler here, so apply grains of salt.
Aside from value semantics, ask yourself: Why do we have structs? What is the advantage?
One advantage is that we can (read: want to) store them on the stack (resp. in an object frame), i.e. just like primitive values in other languages. In particular, we don't want to allocate dedicated space on the heap to point to. That makes accessing struct values more efficient: we (read: the compiler) always knows where exactly in memory it finds the value, relative to the current frame or object pointer.
In order for that to work out for the compiler, it needs to know how much space to reserve for a given struct value when determining the structure of the stack or object frame. As long as struct values are trees of fixed size (disregarding outgoing references to objects; they point to the heap are not of interest for us), that is fine: the compiler can just add up all the sizes it finds.
If you had a recursive struct, this fails: you can implement lists or binary trees in this way. The compiler can not figure out statically how to store such values in memory, so we have to forbid them.
Nota bene: The same reasoning explains why structs are pass-by-value: we need them to physically be at their new context.
Quick and easy hack workaround: just embed it in an array.
struct A {
var otherA: [A]? = nil
init() {
otherA = [A()]
}
}
You normally cannot have a reference cycle with value types simply because Swift normally doesn't allow references to value types. Everything is copied.
However, if you're curious, you actually can induce a value-type reference cycle by capturing self in a closure.
The following is an example. Note that the MyObject class is present merely to illustrate the leak.
class MyObject {
static var objCount = 0
init() {
MyObject.objCount += 1
print("Alloc \(MyObject.objCount)")
}
deinit {
print("Dealloc \(MyObject.objCount)")
MyObject.objCount -= 1
}
}
struct MyValueType {
var closure: (() -> ())?
var obj = MyObject()
init(leakMe: Bool) {
if leakMe {
closure = { print("\(self)") }
}
}
}
func test(leakMe leakMe: Bool) {
print("Creating value type. Leak:\(leakMe)")
let _ = MyValueType(leakMe: leakMe)
}
test(leakMe: true)
test(leakMe: false)
Output:
Creating value type. Leak:true
Alloc 1
Creating value type. Leak:false
Alloc 2
Dealloc 2
Is there, however, a possibility of having reference cycles with value types only?
Depends on what you mean with "value types only".
If you mean completely no reference including hidden ones inside, then the answer is NO. To make a reference cycle, you need at least one reference.
But in Swift, Array, String or some other types are value types, which may contain references inside their instances. If your "value types" includes such types, the answer is YES.

Capturing a struct reference in a closure doesn't allow mutations to occur

I am trying to see if I can use structs for my model and was trying this. When I call vm.testClosure(), it does not change the value of x and I am not sure why.
struct Model
{
var x = 10.0
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
testClosure =
{
() -> () in
model.x = 30.5
}
}
}
var vm = ViewModel(model:&m)
m.x
vm.testClosure()
m.x
An inout argument isn't a reference to a value type – it's simply a shadow copy of that value type, that is written back to the caller's value when the function returns.
What's happening in your code is that your inout variable is escaping the lifetime of the function (by being captured in a closure that is then stored) – meaning that any changes to the inout variable after the function has returned will never be reflected outside that closure.
Due to this common misconception about inout arguments, there has been a Swift Evolution proposal for only allowing inout arguments to be captured by #noescape closures. As of Swift 3, your current code will no longer compile.
If you really need to be passing around references in your code – then you should be using reference types (make your Model a class). Although I suspect that you'll probably be able to refactor your logic to avoid passing around references in the first place (however without seeing your actual code, it's impossible to advise).
(Edit: Since posting this answer, inout parameters can now be compiled as a pass-by-reference, which can be seen by looking at the SIL or IR emitted. However you are unable to treat them as such due to the fact that there's no guarantee whatsoever that the caller's value will remain valid after the function call.)
Instances of the closure will get their own, independent copy of the captured value that it, and only it, can alter. The value is captured in the time of executing the closure. Let see your slightly modified code
struct Model
{
var x = 10.0
mutating func modifyX(newValue: Double) {
let this = self
let model = m
x = newValue
// put breakpoint here
//(lldb) po model
//▿ Model
// - x : 30.0
//
//(lldb) po self
//▿ Model
// - x : 301.0
//
//(lldb) po this
//▿ Model
// - x : 30.0
}
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
model.x = 50
testClosure =
{ () -> () in
model.modifyX(301)
}
model.x = 30
}
}
let mx = m.x
vm.testClosure()
let mx2 = m.x
Here is what Apple says about that.
Classes and Structures
A value type is a type that is copied when it is assigned to a
variable or constant, or when it is passed to a function. [...] All
structures and enumerations are value types in Swift
Methods
Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
However, if you need to modify the properties of your structure or
enumeration within a particular method, you can opt in to mutating
behaviour for that method. The method can then mutate (that is,
change) its properties from within the method, and any changes that it
makes are written back to the original structure when the method ends.
The method can also assign a completely new instance to its implicit
self property, and this new instance will replace the existing one
when the method ends.
Taken from here