I am curious if the next code will lead to the strong reference cycle?
enum Type {
case some(obj:Any)
}
class Entity {
var type:Type
init() {
type = Type.some(obj:self)
}
}
Yes. Any is implicitly strong. If you pass a reference type, it will be a strong reference. It's not quite a "cycle" since nothing "retains" an enum, but as long as the value exists (or any copy of the value), it will hold onto Entity and prevent it from being deallocated.
Imagine if it were not true. What would .some(obj: NSObject()) contain? If Type.some did not increase the retain count, the NSObject would vanish. (Since this is very similar to an Optional, that would be very surprising, since many T? would immediately become nil.)
BTW, this is easily and usefully explored by creating a deinit method on Entity.
Related
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.
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.
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 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.
I have swift class with various properties, some of which have optional types.
class UserObject: PFUser{
//optional property
var optionalPhotoURL:String? {
get {
if let optionalPhotoURL:String = objectForKey("optionalPhotoURL"){
return optionalPhotoURL
}
//not needed but just for emphasis
return nil
}
//I am unable to set UserObject.optionalPhotoURL = nil with this setters
set {
if let newPhotoURL:String = newValue! {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
}
}
I am unable to set optionalPhotoURL as nil, if it already had a previous value assigned to it.
I guess my question is, how do i "unset" an optional property with custom setter?
Update
These setters all crash
set {
if let newPhotoURL:String = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
and this
set {
if (newValue != nil) {
setObject(newValue!, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
What you have here is a computed property.
Swift properties can either be computed or stored. We can observe value changes in our stored properties by using didSet and willSet but here we still have a stored property.
In your case, since you have overridden set and get*, you don't have a stored property, you have a computed property. If you want a computed property to have a backing storage, you must create that independently.
So you may want something like this:
class FooClass {
private var storageProperty: String?
var accessProperty: String? {
get {
return self.storageProperty
}
set {
self.storageProperty = newValue
// or whatever logic you may like here
}
}
}
*: You can't override set without also overriding get. You can however override get without overriding set--this makes a readonly computed value.
Moreover, it's important that we implement our storage properties in this way over relying on key-value coding.
For starters, setObject(forKey:) approach doesn't even work on pure Swift types. This will only work on objects which inherit from Objective-C types. It's an inherited method from NSObject's compliance to NSKeyValueCoding protocol. Why the base object of Objective-C conforms to so many protocols is beyond me... but it does and there's nothing we can do about it.
If we have a code base in which some of our objects are inheriting from Objective-C objects (which basically any project will have, UIViewController, etc), and some of our objects are pure Swift objects (which you will tend to have when you're creating your own Swift classes from scratch), then our Swift objects will not be able to implement this same pattern. If we have some objects of both types, we'll either have to implement the pattern I show above for all of them (and then we have consistency) or we'll have to implement one pattern for some types and another for other types (Swift structs would definitely have to implement the above pattern, you can't just make them inherit from NSObject) (and then we have inconsistency, which we don't like).
But what's far worse about setObject(forKey:) is that the first argument of this method always will be of type AnyObject. There is no type safety to the method at all. Where things are stored via setObject(forKey:) is based purely on the key which we use. When we use setObject(forKey:), we take a pile of type-safety advantages that Swift gives us and we throw them out the window. If we don't care to leverage the advantages Swift gives us over Objective-C, why are we writing it in Swift at all?
We can't even make the stored property private when we use setObject(forKey:). Anyone who knows the key can call setObject(forKey:) and set that object to whatever they want. And that includes objects which are not strings. All we have to do to introduce a crash to this codebase is write a class extension or subclass which has a key collision on a different type other than what you've used (so maybe an NSData value for the same key). And even if it doesn't happen to be a different type, simply duplicating the same key for multiple properties is going to introduce bugs... and bugs that are hard to debug.
Never set a value of a computed property in its set scope by calling itself !
This causes an infinite loop and the app will crash.
I don't know which API setObject:forKey belongs to, but in the case of nil you are supposed to remove the object
set {
if let newPhotoURL = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
} else {
removeObjectForKey("optionalPhotoURL")
}
}
Your property optionalPhotoURL is a computed property, it does not store any values:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
You might want to create an additional property which actually stores the value. However, why do you want to set it to nil, since you are not deleting they object in case of nil.