When are objects that hold unowned references deallocated? - ios

I was playing with unowned references. As I understood from the WWDC videos, unowned references can't be nil, and they do not increase the retain count of whatever object they reference. I thought that if an unowned reference is deallocated, then the object that held the unowned reference is also deallocated.
Consider the following code:
class Parent {
var child : Child?
func foo() {
println("Hello")
}
}
class Child {
unowned let parent : Parent
init(parent: Parent) {
self.parent = parent
}
}
var parent : Parent? = Parent()
parent!.child = Child(parent: parent!)
weak var child = parent!.child
parent = nil
child!.parent.foo()
This code works! How come child exists, and moreover, how come parent apparently still exists? I had thought that after setting parent = nil, child would also be nil. It seems as if the unowned reference is acting as if it were a strong reference.
Any ideas as to why this code works?

Your code will most likely only work in the playground, where the memory management is a little... fuzzy.
When I ran this in Xcode, it crashes as you'd expect. The playground is meant to make it easy to test the syntax, play with some classes, etc. It's not the best place to play around with weak/unretained variables.
I haven't found any documented sources describing how exactly the memory is managed in a playground, but it's definitely different from how it will be in an actual runtime.

Related

Will this situation create a retain cycle

My sample code like this (just a sample):
[self.view touchActionWithCompeletion:^(NSSting *text){
self.label.text = text;
}];
The block is a parameter of a method, the method is a instance method of self.view, then I access self in block. If self.view is a strong property, will this situation create retain cycle? And will self.view strong reference the block?
Adding my comment above as answer, after testing the code myself to confirm the logic I mentioned,
I think it should not, dead lock ( I mean memory leak, two strongly held objects holding the reference to each other and never being de-allocated hence I mentioned deadlock) will happen only if you pass a strong reference of an object to the block (in this case self) and then the passed object holds a strong reference to block itself (directly or indirectly).
Hoping that method touchActionWithCompeletion will not save the block passed to it with a strong reference this should not result in a retain cycle
EDIT:
Tested your code and deinit gets called as expected.
Here is what I tried,
class MyView : UIView {
func touchActionWithCompeletion(block :(NSString)->()) {
block("abcd");
}
}
class ThirdViewController: UIViewController {
var myViewInstance = MyView()
#IBOutlet var c: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.myViewInstance.touchActionWithCompeletion { (abcd) in
self.c.text = abcd as String
}
}
deinit {
print("deinit called")
}
}
As expected deinit called.
Only thing to notice here, method touchActionWithCompeletion will not store the block passed to it with strong reference. It simply executes it. So my answer above holds true in this case.
EDIT 2:(Clarifying my statement in answer)
I happened mention the passed object holds a strong reference to block itself (directly or indirectly) I guess I need to explain why I mentioned indirectly.
Consider this case, Deadlock will happen if View holds a strong reference to the block passed to its method. Though the strong object passed here to the block is self and self does not hold the reference to block directly, it still result in deadlock if View holds a strong reference to block.
Reason Self - holds a strong reference -> View - holds a strong reference -> Block - holds a strong reference -> Self
Hence deadlock. Though self does not hold the block directly, because it holds the block indirectly, hence deinit on self will not be called. Hence I happened to mention the passed object holds a strong reference to block itself (directly or indirectly)
Hope it helps

How do i release allocated memory for array?

I am not understanding how to give weak refrence to the array or release allocated memory of array, can anyone tell me how to fix this leak?
var menuDetails:[[String:Any]] = []//this my global array object
Getting following leak even i am using ARC.
Screenshot for array memory leak!
I was just scared about that memory leak,can anyone tell how do i fix it?
You don't want to use a weak reference. If you do that your array will get released immediately.
weak var weakArray: [[String:Any]]? = []
Will contain nil as soon as you create it.
Instead, you should set the array to nil (or empty) once you're done with the contents:
You could use `menuDetails.removeAll() to delete all the entries in the array, or you could change your declaration to make it an Optional
var menuDetails:[[String:Any]]? = []//this my global array object
And then set it to nil when you're done with it:
menuDetails = nil
An object will only be retained if another object has a strong reference to it. As soon as your view controller disappears, it will most likely be deallocated as well, which automatically removes its strong references to other objects. Thus, if imageArray is strongly referenced only by your disappearing view controller, the memory will automatically be released. You do not need to use an autoreleasepool.
In order to store weak references in arrays and/or dictionaries, you need an intermediate structure.
for example:
struct WeakRef
{
weak var object:AnyObject?
init( _ objectRef:AnyObject?)
{ object = objectRef }
}
// use WeakRef when you add object instances to your dictionary (or array)
menuDetails[0]["objectKey"] = WeakRef(yourObject)
// you will need additional code to get the actual object out of the intermediate structure
// and given that it is a weak reference you'll also need to deal with its optionality.
if let yourObject = (menuDetails[0]["objectKey"] as? WeakRef)?.object as? YourClass,
{
// ... do your thing with your object ...
}
The syntax could probably be made more legible by wrapping this in custom operators and generics but this is the general approach to it.

How to set up cross-referencing between UIViews in Swift

First q here, so trying to get protocol right...what I've done works, in that the data and views display correctly, but memory is not deallocating (still getting used to ARC after many years of allocating/deallocating), and I'm trying to figure out the right strategy. Document based app. When doc is created, view controller is instantiated, which creates several views which need to refer to each other for size/position/methods, and all of which need access to the doc data.
class MyDoc: UIDocument {
var data: Int
etc...
}
class MyController: UIViewController {
var doc: myDoc! // code which creates MyDoc instance assigns self to this property
var thisView1: MyView1!
var thisView2: MyView2!
thisView1 = MyView1(...)
thisView2 = MyView2(...)
thisView1.theOtherView2 = thisView2
thisView2.theOtherView1 = thisView1
thisView1.doc = self.doc
thisView2.doc = self.doc
}
class MyView1: UIView {
var theOtherView2: MyView2!
var doc: MyDoc!
}
class MyView2: UIView {
var theOtherView1: MyView1!
var doc: MyDoc!
}
I don't think I excluded anything meaningful. Assigning thisView1 and thisView2 to each other creates a strong reference cycle, right? I tried combining an unowned property on one with implicitly unwrapped on the other, per The Swift Programming Language, but kept having trouble with the init() methods of the views. Is using weak references and then unwrapping the optional all the time (though I make sure there's a valid value before proceeding from viewController) the only thing that'll work? I've read so many explanations that each new one now confuses me more.
Thank you!

How do I deinit a lazy var in Swift?

I've been reading a bunch about Swift initilization lately, and one solution that appears to have some merit is utilizing lazy variables to avoid the doom and gloom of optionals, especially when extending UIViewControllers or other classes along those lines. With that in mind, I've got code that looks like this:
final class MyViewController : UIViewController {
lazy private var myOtherViewController: MyOtherViewController = MyOtherViewController()
deinit {
// myOtherViewController = nil // Can't do this. Expression resolves to an unused l-value
}
override func viewDidLoad() {
super.viewDidLoad()
myOtherViewController.foo();
}
}
// elsewhere...
final class MyOtherViewController : UIViewController {
deinit {
print("Deinit!")
}
}
In the example here it appears that MyOtherViewController's deinit method never seems to fire, but I also have no way to make myOtherViewController deinit. Setting it to nil isn't allowed. Is there something I'm missing that forces MyOtherViewController to retain? Or have I just been impatient with the garbage collector?
To do this, your lazy variable would have to be declared as optional even though you intend to initialize it as soon as the value is needed (i.e. lazily).
class MyObject {
func run() {
print( "MyObject :: run()" )
}
init() {
print( "MyObject :: init" )
}
deinit {
print( "MyObject :: deinit" )
}
}
class MyContext {
lazy var myObject:MyObject? = MyObject()
}
let myContext = MyContext()
myContext.myObject?.run() //< "MyObject :: init"
myContext.myObject = nil //< "MyObject :: deinit"
Also, I disagree with the notion of the "doom and gloom of optionals"—one only need know which of the many available techniques is most convenient and practical way handle them, and how to avoid allowing too many permutations of state to exist among combinations of optional and non-optional values in a given context. Furthermore, an optional is actually exactly what you want here because you intend to nullify it. Employing an optional doesn't mean that a value will be nil for now until you initialize it, but rather that it may be nil at any point in its life, even if it is defined at declaration or any other time beforehand. If avoiding optionals is truly that high of a priority for you, you'd have to take a step back and re-evaluate your architecture to create a situation where you no longer have the need to de-initialize the value.
I agree with Grimxn, that this pattern of setting that property to nil (and thus needing to make it optional in order to be able to do that) is unnecessary. When MyViewController is deallocated, it automatically releases its strong reference to MyOtherViewController.
The only time you need to manually nil this property is when you have to resolve a strong reference cycle (and if you had such cycle, you can't resolve that in deinit, but rather viewDidDisappear or something like that).
If you're not seeing this other view controller get deallocated, then I'd suggest finding the source of the strong reference cycle and resolving that.

How to work with Automatic Reference Counting (ARC)?

In Swift, we mostly use many references of classes like ,
UITableView
UIStepper
UILabel
NSTimer
UISlider and etc..
one example:
var slider : UISlider!
My question is whether we have to create all these as weak refernces by prefixing it as weak, so that ARC will not have a strong hold on it so ARC can delete it as when needed or just creating a strong reference and make it to nil at the viewDidUnload deligate ??
example :
slider = nil
To the point I actually don't know how to manually use ARC or manually handling ARC is not at all needed ?? I have no idea about this meamory handling
Pls do share if u ever came across this and found a solution...
Thanks in advance....
ARC (Automatic Reference Counting) in Swift is explained pretty well in the official documentation.
Below you can find a very simple recap of 4 important aspects of ARC.
1. Basics
ARC associates to each instance of a Class a retainCount integer.
This value represents the number of strong references to that specific instance.
When this number becomes 0 then the memory used by the instance is freed.
class Something {}
var aVariable = Something()
// now the reference counting for this particular instance of Something is 1
Now our instance of Something is keept in memory since its retainCount value is 1.
var anotherVariable = aVariable
Now we have 2 strong references to our instance of Something. Good! Its retainCount now is 2 and the instance is still kept in memory!
aVariable = nil
The retainCount has just become 1. No problem, the instance is still in memory.
anotherVariable = nil
Finally the retainCount of our instance has become 0. This means that the instance has been freed and can no longer be accessed.
2. Should you set to nil your variables when you're done with them?
Nope. Infact when a variable goes out of scope ARC automatically decrease the retainCount of the referenced instance.
In the following example, before the last } the retainCount of the instance of Something gets decreased and reach value 0 (and is freed).
func doSomethingUseful() {
let something = Something()
// ... do very important stuff here
}
So in a common scenario you don't need to set variables to nil in order to force ARC to free the referenced instance.
Another example:
class Son {}
class Father {
var sons: [Son]
init (sons: [Son]) {
self.sons = sons
}
}
func lifeGoesOn() {
let son = Son()
// here the referenceCout of the instance of Son is 1
let father = Father(sons: [son])
// here the referenceCount of the instance of Son is 2...
// now variable son goes out of scope so the reatinCount of the instance of Son becomes 1
// also father goes out of scope, so the variable father.sons goes out of scope as well, so the `retainCount` of the instance of Son becomes 0
// and so both the instances of Father and Son gets freed
}
You can see this like a domino effect. When an instance is freed, all its references to other instances are removed. So the retainCounts of the referenced instances gets decreased. And if becomes 0 they are released. And so on...
3. Retain cycles
Ok, what happen if I have 2 classes as follow?
class Son {
let father:Father
init(father:Father) {
self.father = father
}
}
class Father {
var sons: [Son]
init (sons: [Son]) {
self.sons = sons
}
}
Lets create now a reference from a father to its son and viceversa from the son to its father.
func lifeGoesOn() {
var father = Father(sons:[])
// retainCount of the instance of Father is 1
var son = Son(father: father)
// retainCount of the instance of Father is 2
// retainCount of the instance of Son is 1
father.sons.append(son)
// retainCount of the instance of Father is 2
// retainCount of the instance of Son is 2
// Now we have a problem
}
At the of the function the father variable goes out of scope so the retainCount of the instance of Father becomes 1.
Similarly the variable son goes out of scope and the retainCount of the instance of Son becomes 1.
The problem here is that the instance of Son references the instance of Father (keeping this instance in alive memory). And the instance of Father references the instane of Son. These 2 instances should not be in memory anymore. They are not accessible by the programmer since all the variable to reference them are gone.
This is a problem.
4. Weak references
When you structure your code you should pay attention to strong retain cycles. Let's how to refactor our code to fix this.
class Son {
weak var father:Father?
init(father:Father) {
self.father = father
}
}
Now the reference from a Son to its Father is weak. This means it does not count when ARC calculates the number of (strong) references to an instance. And this fix the problem seen in the previous paragraph.
I hope the subject is a little bit more clear now. There are several scenarios I did not cover. Again, the official documentation is pretty good and exhaustive.
Update (to better answer the comment below)
If you have a custom UIViewController (lets call it MyCustomViewController) and this class has a strong property to an object let's see what happen.
class MyCustomViewController : UIViewController {
var something = Something()
}
class Something {
init() { // called when memory is allocated
debugPrintln("The instance of Something has been created")
}
deinit { // called when memory is freed
debugPrintln("The instance of Something has been freed")
}
}
When you present a MyCustomViewController, an instance of MyCustomViewController is created. Then an instance of Something is created as well.
Now the instance of MyCustomViewController is referenced by the UINavigationController so has retaintCount = 1.
Similarly the instance of Something is referenced by the instance of MyCustomViewController so it has retainCount = 1.
So the instance of UINavigationController keeps alive the instance of MyCustomViewController. And the instance of MyCustomViewController keeps alive the instance of Something.
UINavigationController -(strong)-> MyCustomViewController -(strong)->
Something
Next you decide to dismiss MyCustomViewController, so iOS animates it to leave the screen. When it is no longer visible it is removed the reference from the instance of UINavigationController to the instance MyCustomViewController.
UINavigationController -(REMOVED)- MyCustomViewController -(strong)->
Something
This means that the retainCount of the instance of MyCustomViewController becomes 0 because: no one is referencing it now!
So the instance of MyCustomViewController is going to be removed from memory. In this process its properties are nulled.
UINavigationController -(REMOVED)- [free memory] -(REMOVED)- Something
Now the retainCount of the instance of Something has become 0.
So it will be removed from memory as well.
UINavigationController -(REMOVED)- [free memory] -(REMOVED)-> [free memory]
Finally, I overidden the init and deinit methods of Something so you can keep track of the allocation and deallocation of a related instance. Looking at the log (or using a breakpoint) you can verify what I said here.
Hope this helps.
If you are talking about view controller properties that are initialised by the view itself (such as UILabel or pretty much any subclass from UIView that you define in IB), Xcode will assign them as weak automatically, as the view (and not the view controller) have created the strong reference.
Most of the times you don't need to manually add weak to your properties, unless you have defined a strong relationship somewhere else in your code (which is the typical case when you have delegates).
ARC mostly just works. You normally do not have to worry about declaring weak when using Cocoa classes such as the ones you listed.
You only have to consider it when you have different classes you've developed yourself that have bi-directional references. (Apartment class and Person class in Apple's example).

Resources