First of, I am using ARC and targeting iOS4+
I have a custom class that needs a reference to a custom UIViewController.
Unless I have missunderstod something, having the property retain on that reference means that whenever my class destructs, the UIViewController destructs aswell?
Or does it mean that both the appdelegate (which created the UIViewController) and my custom class needs to be deallocated in order for the UIViewController to be deallocated?
So I also read about __unsafe_unretained property. Can my custom class simply use that without complications to reference the UIViewController? Since the appdelegate would deallocate the UIViewController in the end anyway, there is no risk of a dangling pointer?
Thanks
EDIT: The custom class is a singleton object that will live through the entire process if it matters
Each object has a retain count that essentially determines whether or not it needs to stick around. In this case your AppDelegate has retained the UIViewController already (retain count of 1), but that does not mean that your custom class cannot also retain the UIViewController (retain count of 2). So your second scenario is closer to the truth: when your custom class destructs and releases the UIViewController the retain count will drop back to 1. Then, when the AppDelegate destructs and releases it the count will drop to 0 and the object will be destroyed.
To take this a step further, if inside of your custom class you assigned the UIViewController to another bult-in or custom class which also retained it the count would keep going up and then it would drop back as each of those objects in turn released its interest.
Related
I am interested in retaining cycles.
Let assume we have two views, A and his subview B.
I know that if B has a (custom) delegate defined as
class B: UIView {
var delegate : CustomDelegate?
}
and I set inside A :
b.delegate = self
This create retain cycle, because B has strong reference to A and A has strong reference to be, so neither could be freed.
Question :
What if I have object inside A and I want to pass it to the B object.
class B: UIView {
var object : SomeObject?
}
and inside A :
b.object = self.object
Is this a retaining cycles too? I can't figure this out.
When object (in A) is created it's reference is 1. When it is passed to the B it's reference is 2. But when A try to deallocate itself : When deallocate object in A it reduce reference to 1 and when he try to deallocate B the object reference should go to 0. Is this mean that there is no retaining cycles? Or did B holds indirect reference to A trough object?
Second question :
What could I lose if all object inside B would be weak references? Or better witch object need to be weak?
I assume your first (and only real) question is intended to imply something like this:
class A : UIView {
var object : NSObject
}
class B : UIView {
var object : NSObject
}
... and then we posit that we have an A and a B where the B is a subview of A. So then the A might say:
(self.subviews[0] as! B).object = self.object // or similar
... and you want to know whether there's a retain cycle involved here. No, not in the general case. There are two objects, an A and a B, and they each have a strong reference to the same third object, i.e. something that is neither this A nor this B. There's nothing wrong with that, and indeed it could be crucial that the A and the B both retain the third object. We might question the legitimacy of A telling B what its object should be, and we might legitimately be disturbed by the possibility that the A could mutate this third object behind the B's back (or vice versa); but from a memory management point of view, nothing of interest has happened.
What could I lose if all object inside B would be weak references
You could lose everything. Remember, normal (strong) references are a way of keeping the referenced object alive (retain); that is what memory management of properties is all about. Assigning to a weak reference, on the other hand, doesn't do that, and thus can cause the assigned object to disappear immediately, if nothing else is retaining it. Weak references are only for cases where the lifetime of the referenced object is correctly and entirely determined elsewhere (as in, a superview determines the lifetime of its subviews).
I found something that I can't understand in UICollectionView header file. I found that the delegate has an assign property
#property (nonatomic, assign) id <UICollectionViewDelegate> delegate;
This question is only for my basic understanding as the rule says the delegate should have a weak property. And according to my personal knowledge, assign won't reference count the delegate object but it will surely still have a reference to a garbage value if the object is deallocated.
How can I understand this piece of code?
strong and weak were introduced alongside Automatic Reference Counting (ARC). UIKit moved to ARC with iOS 9, and if you look at the iOS 9 header (using Xcode 7) you will see that this property is now weak.
You are right: with the property as assign (which is equivalent to unsafe_unretained), if the delegate is deallocated while the collection view is alive, the collection view’s delegate property will point to where the deallocated object used to be and probably cause a crash when it is referenced. This is not usually a problem because the delegate is often the view controller owning the collection view so usually outlives the view. However, this is not a guarantee, which is why you should set assign delegates that point to you to nil in your dealloc.
Relevant Stack Overflow questions:
Objective-C ARC: strong vs retain and weak vs assign
Set delegates to nil under ARC?
ARC delegate memory management
I can't understand why it is correct to define a delegate with weak pointer :
#property (nonatomic,weak) id delegate;
I can't realize why isn't necessary to retain a reference to the delegate... i don't want the object that i use as the delegate to be deallocated... thus, i would prefer using a strong reference not a weak!
In many cases the delegate is the same object where the instance of my class will be created, in this case creating a weak reference would be a great solution to avoid retain cycle... but what if I choose a totally different object as the delegate ?
I searched for other questions on stack overflow but I can't find something that can help me to fully understand this situation.
The reason that objects weakly retain their delegates is to avoid retain cycles. Imagine the following scenario: object a creates b and retains it, then sets itself as b's delegate. a is released by its owner, leaving a retain cycle containing a and b. This is actually a very common scenario. Consider a view controller that owns a view and acts as that view's delegate. In this case, the view should not retain the controller—as a mater of proper MVC architecture and to prevent retain cycles.
Though retain cycles are a valid concern, the reasoning for a weak reference is more related to apple's perspective on how to use the delegation pattern with uikit and other elements out of the box which is explained here:
http://developer.apple.com/library/IOs/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
Specifically:
"The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object."
If the delegate deals with managing the delegated tasks of several objects then those objects need not retain the delegate and should not bear the responsibility of dealllocating the delegate as it might be used by other objects. The weak reference enforces the concept that the management of the delegate is not the delegators responsibility.
An example in objective c is a one delegate being used for multiple table views, like when using a table view and a searchdisplaycontroller with a uisearchbar. Apples examples use the controller as the delegate, but reasoning still holds when using one custom delegate for both the main table view and the results table view for your search. That custom delegate would likely be retained by your controller in order to be provided to both table views.
This is fundamentally different from the basic delegation pattern that is referred to in other languages where the delegate is often created by the delegator and each instance may manage a its own delegate instance.
This is to avoid retain cycles. Apple offers an informative guide on advanced memory management explaining the situation and how best to deal with it. In ARC, they are now known as strong reference cycles, which are explained in the Transitioning to ARC Release Notes.
Previously you would define a property for a delegate like this,
#property (nonatomic, assign) id delegate;
But in ARC, you can define it thus,
#property (nonatomic, unsafe_unretained) id delegate;
Or, for example, if you have a protocol named <MyObjectDelegate>, you can also define the delegate in this way,
#property (nonatomic, weak) id <MyObjectDelegate> delegate;
In other words, in ARC if you have a protocol, you can declare a delegate weak. Otherwise, unsafe_unretained.
As a common practice, if we have two objects holding references with each other, we make the "child" object in a "parent-children" relationship a weak reference.
For delegation patters in iOS, the delegated object is the parent, because there is no need for the delegate caller to exist without the delegated object. For example, you have a sentence object with delegate object for method sentenceShouldEnd. Your paragraph object is the delegated object for your sentence object. Obviously the paragraph object is actually the parent, and in your sentence object you should keep your delegate as a weak reference.
To your point you assign the delegate to self, your understanding is wrong. We should never assign delegate to itself. Why you buy your ticket yourself if you feel it is necessary to hire an agent to buy the ticket for you? You are saying two completely different concepts. When you define a delegate object as property, it's used a weak reference in the object it is defined in(lets say A, i.e. the delegate object is a property of A). The delegate is assigned when you init A(let's say in B), then most likely you would assign A.delegate to self, which is acturally B. You see the parent-child relationship here?? You alloc memory for A in B. You hold A in B. A does not exist without B. You are not assigning the delegate to A!!!!
In iOS 7 I used to define weak reference to popover controller inside my view controller (which displays in popover). I used this reference to popover controller in order to dismiss popover programmatically. Also, I defined delegate of popover controller in order to track dismissing events (popoverControllerShouldDismissPopover etc).
In iOS 8 it stops working. Investigation shows that weak reference point to nil after some point. The delegate stops working as well (as I understand it's because delegate was defined in popover controller which got destroyed in iOS 8 for some reason after popover displays).
Problem was solved by changed property to be strong reference.
For some popovers (I have bunch of them) I had to add strong reference only for the reason to keep popoverController alive because I need the delegate to work. It's obvious hack. I added property which I don't really need nor use.
Could you please clarify if it's right approach. My concern is that strong reference may lead to memory leaks. Also I don't quite understand why popoverController get destroyed in iOS 8 while popover still on the screen.
This is my view controller with weak property. After changing weak to strong to start working well under iOS 8:
#interface TFDSuggestionViewController : UIViewController
...
#property (weak, nonatomic) UIPopoverController *myPopoverController;
...
#end
This is how I assign value to my property and delegate in prepareForSegue method in calling view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"suggestions"]) {
TFDSuggestionViewController *suggController = ((TFDSuggestionViewController *)[segue destinationViewController]);
suggController.myPopoverController = ((UIStoryboardPopoverSegue *)segue).popoverController;
((UIStoryboardPopoverSegue *)segue).popoverController.delegate = self;
}
}
Thank you for you advice!
In the old days of manual memory management there was something called a reference count. It was essentially the number of times an object was retained (strong reference) by other objects or the App. In the more recent ARC (Automatic reference counting) we no longer need to do [object retain] and [object release]. These actions are handled for us by the compiler.
Now to your situation. A weak reference does not increase the reference count of the object you are referencing. So if you create an object in a scope, assign a weak reference to it, then leave the scope your object's reference count is 0.
-(void)SomeMethod
{
ClassObject *object = [[ClassObject alloc] init];
//object's internal reference count is now 1
self.myPopoverController = object;
//Since myPopoverController is a weak reference, object still has reference count of 1
//Some other code that does things and stuff.
}
//We just closed the scope, so object's reference count is now 0
//ARC is free to release the object to free it's memory, causing any
//weak references to return nil
In the example above it shows a very simple object life cycle. Once you understand the life cycle you can see why a weak reference will do you absolutely no good in this situation.
As to why it worked in iOS7 and not in iOS8 the only answer that I have is that iOS8 is likely much more efficient in garbage collection. If you ran it a million times in iOS7 I'm sure you would find at least one example of the exact same problem happening. It was a flaw in the code that the new OS makes more prevalent.
If you want the object to stay alive you need to have at least one strong reference to it. The only precaution is that when you call dismiss you should nil the strong reference. Then there should be no adverse memory issues to resolve.
Another bit that is very important. The UIPopoverController is not the same object as what is visible on screen. What is visible on screen is the UIPopoverController.view. The view is still retained by the view hierarchy, but the controller needs to be retained by you in order for it not to get released. Once the UIPopoverController is released the view's delegate will be nil since view.delegate is also a weak reference.
Study the object lifecycle. It will help you avoid garbage collection problems that will definitely arise in the future as the OS gets more and more efficient in memory handling.
Have an interesting issue where there is a class that is referenced in an XIB layout (subclass of UIScrollView) and is not being de-allocated according to Instruments / Allocations and does not break in it's dealloc routine. Let's call it Sclass1.
There is a using class (let's call it Uclass) that has the XIB file and the outlet.
#property (nonatomic, weak) IBOutlet Sclass1* sclass1;
This is hooked properly to the XIB file layout.
Sclass1 is property allocated when the XIB for Uclass is loaded. Uclass does get deallocated and then recreated from time to time and thus we have another instance of Sclass1, but Sclass1 never goes away and can't find another reference to it.
Drill down in Instruments shows the one Malloc and that is it.
fyi, the class gets started with
[UIClassSwapper initWithCoder:]
If an object doesn't get deallocated under ARC, it means a strong reference to it exists. Since your property is weak the object must be owned strongly by something other than the Uclass object (Otherwise it would get deallocated immediately after the XIB has loaded). In the code you've provided it isn't clear what the actual strong owner of this object is, but I assume it could be one (or more) of the following:
Since the object's class is a UIView subclass, it may be (strongly) referenced by its superview if added as one of subviews. This happens automatically when a XIB file is loaded. If the superview doesn't get deallocated neither will the SClass object. You can remove this ownership by calling removeFromSuperview
A strong ownership cycle (retain-cycle) exists somewhere among ivars of the SClass1 object (i.e. one of the strongly-owned instance variables have a strong reference back to its owner - the SClass1). Beware that any block using self directly also keeps a strong reference. Having a strong reference to the block then often leads to a retain-cycle. Save self to a __weak var and pass that to the block instead unless you have a good reason not to.
A manually created strong reference exists by e.g. adding the object to a container or saving the pointer to a non-__weak variable.
Try finding and removing these strong ownerships. Only after all of them are removed the object can be deallocated.
Since your property is weak and it's still not deallocated, look for strong references to Sclass or it's owner, Uclass. Maybe you are using Uclass(or Sclass) in block directly, without __weak typeof(self) weakSelf dancing and this block creates retain cycle. Also watch for parent-child relations and delegates. Maybe there is delegate which is strong instead of weak or two controllers hold strong references to eachother.
Also, if you want to have more detailed answers, please post more relevant code.
I think your #property should be strong for a class :
#property (nonatomic, strong) IBOutlet Sclass1* sclass1;
Because strong is the equivalent to retain and ARC will manage the release for you.
You will have more information with the Apple Documentation about Transitioning to ARC Release Notes in the section on property attributes.
I recently had the same symptoms - To solve it in my case, my object was acting as delegate for a number of other objects, so had to release the object from all its delegate responsibilities before it would call dealloc