Why can't I give an unowned constant an initial value? - ios

class Example {}
unowned let first = Example()
This produces the error:
Attempted to read an unowned reference but object 0x60c000005f20 was already deallocated
I'm trying to dig deep into understanding exactly what keyword unowned does.

From The Swift Programming Language:
Like a weak reference, an unowned reference does not keep a strong hold on the instance it refers to.
You create a new instance of Example, and assign it to your unowned constant first. There is nothing holding a strong reference to your Example instance so it is immediately deallocated. Your unowned constant first is now holding a reference to this deallocated object so you get the error that you are attempting to read a deallocated object.
The unowned keyword is used to create a weak reference to an object where you can guarantee that the lifetime of the referenced object is the same as the referring object. This enables you to prevent reference loops while avoiding the need to unwrap an optional (as would be the case with weak).

Apple's documentation says:
Unlike a weak reference, however, an unowned reference is used when
the other instance has the same lifetime or a longer lifetime.
In your example up there, as soon as "Example()" is called, your new property is deallocated (newis a terrible name for even a property, even if only for a demo :-).
So what could work here would be:
class Example {}
let oneExample = Example() // properties are strong by default
unowned let theSameExample = oneExample

Related

Why weakifying a strong reference by using a local variable doesn't work?

(I understand how ARC works and the difference between weak and unowned. The question is about a specific use of them and why it doesn't work. I'll use unowned in the example below just for simplicity.)
See example below. Note line 10, which is intended to change the passed strong reference to an unowned reference. I thought this would work, but when I used it in my code recently I found I was wrong.
1 import Foundation
2 class MyClass {
3 var uuid: UUID = UUID()
4
5 deinit {
6 print("Deinited!")
7 }
8 }
9 func test(_ d: inout [UUID:MyClass], _ o: MyClass) {
10 unowned let u = o // <- !
11 d[u.uuid] = u
12 }
13 var d = [UUID: MyClass]()
14 test(&d, MyClass())
Run the above code in Playground. The result shows that deinit isn't called, indicating a strong reference to the object is saved in the dictionary.
I wonder why? Does weak and unowned keyword only applies to property? But the above code doesn't generate compiler error and the Swift book does mention it can be used in variable declaration:
You indicate an unowned reference by placing the unowned keyword
before a property or variable declaration.
Can anyone share how you understand it? Thanks!
BTW, I know how to solve the issue (for example, using a wrapper like this). What I try to understand is why the above code doesn't work.
When assigning (a = b), you can't control what kind of reference a is. You can only control what object a refer to.
Here:
d[u.uuid] = u
The code is not saying:
The value associated with the key u.uuid in d is set to the (unowned) reference u.
It's saying:
The value associated with the key u.uuid in d is a reference (not saying what kind) that refers to what u is referring to.
The fact that u is unowned is rather irrelevant. Dictionaries will always store strong references to objects. That's just how they are designed.
In the case of the Weak<T> wrapper, the dictionary will still store a strong reference to Weak<T>, but Weak<T> will store a weak reference to the wrapped T object. That's how it achieves not having a strong reference to the T object.
#Sweeper's answer contains all the points I'll give below. But I'll try to make them a bit more explicit:
Variable represents a storage (a location in memory)
Assignment operation changes the value in the storage
weak and unowned are attributes of the storage. They are not affected by assignment operation.
So the unowned keyword in line 10 in my example code affects only that specific storage location (it's in stack) and have no influence on the attribute of storage used by the global dictionary (as #Sweeper pointed out).

Is it redundant in Swift to use weak and optional for the same variable?

I'm new in Swift and in the Apple docs I see:
Use a weak reference whenever it is valid for that reference to become >nil at some point during its lifetime.
Shouldn't I achieve that just by using "?" for optional types?
in other words:
Do the weak and ? overlap?
The compiler complains if I don't define a variable as optional when is weak, so I feel like I could just remove it and forget about it, but I feel I'm just misunderstanding it.
Thanks!
No, weak and optional are not the same, but there is some interplay between the two.
Optional just means that a variable can be nil, either by assigning nil yourself, or becoming nil through some other means.
The weak keyword has to do with memory management. When a variable is not weak (i.e. it is strong), it means that ARC holds a strong reference to the instance that is assigned. So even when there are no other references to it, the instance will stay alive in memory because the variable still "holds it".
When a a variable is weak, it does not hold a strong reference to it. That means that when there are no other strong references to it, the instance will be deallocated, and the variable will become nil automatically. This also explains why a weak variable must be optional.
The document that you linked to actually explains this quite clearly.
weak is related to memory management that ARC should remove that variable from memory or not. If your variable is weak then ARC would clear that memory to which it is pointing to as soon as all the strong references to that memory destroyed and when the memory is cleared then even the varaible is non-optional it will have nill because its memory is cleared.
But the optional has nothing to do with memory and it is directly related to the variable value that it can either contains the actual value or the nil.
Optional and non-optional properties differ in that optionals may be nil, while non-optional cannot.
weak and strong (property is strong by default without weak keyword) properties differ in that weak don't increase property's retain count, while strong do. If a weak property isn't strongly retained somewhere else, it will be deallocated. weak properties must also be optional.

Swift Memory management when pass a closure as parameter to singleton

I'm aware of the fact that closure can create retain cycles if it is assigned to a property of a class and instance properties of the class are used inside of the closure. But
1) what about the closure is not assigned to the class property but passed as parameter to a singleton's class method ?
2) How the memory is managed in this case ?
In a method of my controller (UIViewController) I have something like:
MySingleton.classMethod(parameters ..., completion: { () -> Void in
/**
doing stuff here
*/
})
If You are not assigning the closure to a property, but just passing it to a function You need to consider if the closure will be escaping or noescape. In Swift 3 by default all closures passed to functions are non-escaping.
Here is a little bit more info on the matter:
"noescape" - the passed closure is invoked before the return of the function
"escaping" - If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping.
Simple explanation : We need to mark closure as escaping when we pass it to a function and the closure will be called after this function returns.
General rule is when the closure is escaping You need to use capture list to prevent retain cycles.
Example
let closure = { [weak someVariable] (name: Type) -> Void in
....
// code
}
Additional info:
One weird thing is that optional closures are treated as escaping. And when we explicitly add escaping keyword, there is a compile error -escaping attribute only applies to function types.
See the below links for more info.
https://bugs.swift.org/browse/SR-2053
https://stackoverflow.com/a/39619298/5388473
https://stackoverflow.com/a/39846519/5388473
Update
The idea of using weak or unowned in the capture lists of escaping closures is that essentially We don't know what will happen with the passed escaping closure, it may be called sometime later from another function or it may be stored in some object, which may lead to a strong retain cycle.
weak vs unowned vs strong capture
For more detailed information check Apple ARC docs.
From Apple docs:
Swift provides two ways to resolve strong reference cycles when you
work with properties of class type: weak references and unowned
references.
Weak and unowned references enable one instance in a reference cycle
to refer to the other instance without keeping a strong hold on it.
The instances can then refer to each other without creating a strong
reference cycle.
Use a weak reference when the other instance has a shorter
lifetime—that is, when the other instance can be deallocated first.
Use an unowned reference when the other instance has the same lifetime
or a longer lifetime.
Keep in mind that the weak approach will add a boiler plate to the code and will be a little bit more slow, because ARC will add code for setting the weak variables to nil on their deallocation. It is a good practice to follow the rules stated above, when choosing weak or unowned.

Does ARC set its reference type instance properties to nil before deallocation?

This question occured to me while reading this.
My question is in reference to the image below:
Once john is set to nil, Person instance no longer has any more strong reference and hence will be deallocated. But Apartment has two strong references and one of which is by the property on Person instance that would be soon deallocated. I believe, this strong reference continue to remain after deallocation and goes out of reach by the code.
So, setting unit14A to nil will remove only one strong reference to Apartment instance and it should not be deallocated as there would be one more strong reference due to the above case.
But, as the document says Apartment instance promptly got deallocated. To me, this can only happen if at the time of Person instance deallocation it sets its apartment property to nil, by that removing that strong reference on Apartment instance. But I couldn't find any documentation to verify this.
So, How does the Apartment instance get deallocated? What happened to the strong reference from the Person instance apartment property?
Can someone help me to understand this?
Objective-C objects are reference counted, meaning that for each object, the system keeps track of how many other objects hold a reference to it. This is object's reference count. Two special messages, retain and release, are used to maintain the reference count behind the scene. Once reference count goes down to zero, the system deallocates the object.
ARC provides "magic" to make reference counting work in a declarative way. The compiler knows every strong reference in your code, so when you do this
myStrongRef = nil;
the compiler quietly inserts a call to release in front of the assignment:
[myStrongRef release];
myStrongRef = nil;
To me [deallocation of Apartment] can only happen if at the time of Person instance deallocation it sets its apartment property to nil, by that removing that strong reference on Apartment instance.
Setting a strong reference to nil one way of breaking a strong reference. It is sufficient, but it isn't necessary. The important thing about setting a strong reference to nil is not the act of setting itself, but what happens immediately before it: the instance referred to by the strong reference gets a release message, instructing it to decrement its reference count. That is precisely what ARC does behind the scene for you: it sends the release message to Apartment, without setting Person's reference to nil.
How does the Apartment instance get deallocated? What happened to the strong reference from the Person instance apartment property?
Once strong reference from Person has sent its release message to Apartment, that strong reference disappears. The actual pointer may be set to Apartment's address, but nobody cares about it, because the Person itself is unreachable.
The life of an object depends on it's reference count, not any actual pointer to the object.
Strong reference is a way of speaking, there is no difference between a strong and weak reference, they are just pointers. The difference is that when a strong reference is created the reference count of the object pointed to in incremented and when deleted the reference count is decreased. When an object's reference count would become zero the object is deallocated.
Your intuition is correct. When an object is being deallocated under ARC all the strong references it holds are first relinquished - essentially they are set to nil, but in practice the implementation may differ.
This is also what happens when a method returns, or a block of code containing declarations exits, all the strong references held in local variables are relinquished.
All the details can be found in the Clang documentation.
HTH
Obviously not before deallocation, but during deallocation.
When an object's reference count goes to zero, the deallocation process starts. The object is marked as "being deallocated". At that point, the object will die (unlike Java, where it can be recovered). If an object is marked like this, it cannot be assigned to weak references (they stay nil), or to strong references.
Then dealloc is called, that is the dealloc methods that you have written. After that, strong references are set to nil, reducing their reference counts, then associated objects are removed, and finally the memory for the object is deleted.

Are Unowned references set to 'nil' when deinitialized?

I'm confused on this topic in swift where it is said that unowned references must always have a value and cannot be optional, also meaning they cannot be set to 'nil'....well I just saw a program on the Apple documents for swift that instance 'A' with an unowned reference to instance 'B' was deinitialized and deallocated right after instance 'B' was deinitialized/deallocated......when a var is deinitialzed/dealloc doesn't it mean they are set to 'nil'??? Instance B is an optional so sure it can hold 'nil' but why did instance 'A' get deinitialized when its supposed to always have a value????
PS: If this helps..... instance 'B' was an optional type with a strong reference to instance 'A'
The point of an unowned reference is to hold a weak reference to something that you are guaranteeing (based on your application logic) will not be deallocated prior to the object that has the unowned reference. You can read more in the documentation.
In a sense it is a similar thing to an implicitly unwrapped optional type (such as String!). You're telling the compiler that you won't ever access the value when it is nil, and if you do your program will crash.
An object is deinitialized when its strong reference count drops to 0, but it is not deallocated until its weak reference count also drops to zero.
"Deinitializing" an object means that its deinit function is executed if it has one, releasing any resource that it holds, and clearing any references that it may have (potentially deinitializing and deallocating more objects). "Deallocating" is when the memory is reclaimed by the runtime. A deinitialized object's reference counting header is still valid.
When you access a weak reference, the Swift runtime ensures that the object is still in an initialized state. If it isn't, the weak reference is set to nil and the deinitialized object's weak reference count is decremented.
Unowned references also count towards the weak reference count. When you access an unowned reference, the Swift runtime also ensures that the object is in an initialized state; but if it is not, instead of clearing the reference (it can't do that because it is not optional), it crashes your program.
This effectively makes an unowned reference behave like an implicitly-unwrapped optional, whereas a weak reference behaves like an optional.
The tradeoff for self-zeroing weak references and clean-crashing unowned references is that an object's backing memory cannot be reclaimed until all of its weak references have been tested or deinitialized, and until all of its unowned references have been deinitialized.
Source: Swift runtime code
It is meaningless to talk about what an unowned variable "holds" after the object it points to has been deallocated, because Swift guarantees that your app will crash if you ever try to access the variable after the object it points to has been deallocated:
Note also that Swift guarantees your app will crash if you try to
access an unowned reference after the instance it references is
deallocated. You will never encounter unexpected behavior in this
situation. Your app will always crash reliably, although you should,
of course, prevent it from doing so.

Resources