Why one weak reference gets deallocated and other doesn't? - ios

I am getting used to using weak and strong references and when to use them and when not and I got to a case like described below (check the comment about the warning)
#interface MPIViewController ()
#property (weak, nonatomic) UIView *subview;
#property (weak, nonatomic) UILabel *label;
#end
#implementation MPIViewController
// ...
// some code here
// ...
- (void)viewDidLoad
{
[super viewDidLoad];
self.subview = [[UIView alloc] init]; // warning here: assigning retained object to weak property
self.label = [[UILabel alloc] init]; // no warnings
[self.view addSubView: self.subview];
[self.view addSubView: self.label];
}
// ...
// some code here
// ...
#end
From description of - (void)addSubview:(UIView *)view:
This method establishes a strong reference to view and sets its next
responder to the receiver, which is its new superview.
This means that this object won't be deallocated after method finishes as it's superview will retain it and hold a strong reference to it and therefore this view will be kept in memory for as long as its superview is there. Am I right here?
I am not sure also if I understand assigning here correctly. Warning says that it will be deallocated straight after the assignment but this sounds wrong as then it wouldn't be possible to assign any variable to a weak pointer as it would get deallocated in the next line of code?
For UILabel same assign works fine, however for UIView it doesn't? Does the compiler treat UIView somehow differently? This really puzzles me how that is even possible.
This code can be fixed easily just by assigning the UIView to a local method variable and then passing it to the setter like this:
UIView *tmpView = [[UIView alloc] init];
self.subview = tmpView;
Variables declared in the method are by default strong so having such a construction removes the warning as the compiler thinks that this variable has a strong reference so weak reference that is then assigned to will be kept as long as the method variable will point to it. BUT! how does that make sense as the tmpView is only a local method variable and will be dumped after method will finish?

To the first question:
Let's have a closer look to it:
self.subview = [[UIView alloc] init];
[UIView alloc] returns an instance with ownership +1. This is assigned to a (non-visible) strong reference, which build the self of -init. -init passes the ownership through. (This is not correct, if -init returns an instance which is not the original receiver, but for your case it is enough details.) So we can think of the return value of -init as an ownership transfer, too.
You assign this instance to a weak variable. In this moment it can be released. (Read: ARC does not promise to do it immediately, IIRC.) the instance variable can be nil before the object is hold by its superview. So this code is dangerous:
self.subview = [[UIView alloc] init];
// _subview can be nil'ed
[self.view addSubView: self.subview]; // add nil
I do not believe that this is your problem, but it can be a problem. – Thinking again about it, it is your problem. Read the edit at the end. –To get rid of it, simply use a strong local variable:
UIView *subview = [[UIView alloc] init]; // defaults to __strong
[self.view addSubView: subview]; // adds an ownership
self.subview = subview;
The second question:
I do not know, why the compiler gives you no warning in the second case. What does happen, if you repair the first case?
At runtime a different handling of both cases is possible, because it is undefined, when the first instance is released. Maybe as a part of optimization a pointer is reused. More detailed:
__strong id completlyHiddenCompilerGeneratedVar;
… = [(completlyHiddenCompilerGeneratedVar=[UIView alloc]) init];
… = [(completlyHiddenCompilerGeneratedVar=[UILabel alloc]) init];
The first instance would be dealloc'ed, when the second instance is created, because it overwrites the internal strong reference.
Again: Repair the first case and tell us, what happens with the second one.

An object need at least one strong pointer to it in order to be kept in memory.
So when you alloc it to a weak pointer that condition is not being met. Make your properties strong if you really need to access these views.

Related

Crash when assigning local object to dataSource of UICollectionView

I have the following setter defined in my class that extends UICollectionView:
// #interface ClipsDataSource : NSObject <UICollectionViewDataSource>
- (void)setProject:(Project *)project
{
_project = project;
ClipsDataSource *dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
dataSource.delegate = self;
dataSource.fetchedResultsController = project.clipsResultsController;
self.dataSource = dataSource;
}
When I run my application I get the following exception:
-[CALayerArray numberOfSectionsInCollectionView:]: unrecognized selector sent to instance 0x174245490
I realised that the instance pointer is the address of the local variable I had used in my setter; the class name is obviously random. From this "discovery" I reasoned that the object was released after assignment.
Normally Xcode will warn me about these issues by saying:
Assigning retained object to unsafe property; object will be released after assignment.
And, sure enough, I see that warning if I change my code to this:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
I have two questions:
Why doesn't Xcode show a warning?
Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).
1) Why doesn't Xcode show a warning?
Because clang is not intelligent enough to figure out that your datasource instance will not be retained elsewhere; only this obvious case will be reported:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
2) Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).
This is done to prevent retain cycles with self referential constructs, which happens quite often in ViewController code.
Imagine that your CollectionViewController is the datasource of CollectionView,
self.collectionView.dataSource = self;
This means:
CollectionViewController retains .collectionView, because View Controllers retain their views by default.
CollectionView retains it's datasource (which is CollectionViewController).
This will cause a retain cycle and therefore Apple decided to use unsafe unretained pointer for .datasource.
Note that both assign and weak pointers will not retain the object that they are pointing. The difference between them is that weak will be automatically nullified when the referenced object is deallocated.
But assign pointer will NOT be nullified, so it will continue pointing to address of memory. Further dereference of that pointer (after deallocation) will probably cause EXC_BAD_ACCESS, or you will get another object (as another object can be written in that address after deallocation).

Retain the delegate of UIImagePickerController

I've wrote a class which gets an image from the camera. Its header is as follows:
typedef void(^ImageTakenCallback)(UIImage *image);
#interface ImageGetter : NSObject <UIImagePickerControllerDelegate, UIPopoverControllerDelegate>
{
UIImagePickerController *picker;
ImageTakenCallback completionBlock
}
-(void) requestImageInView:(UIView*)view withCompletionBlock:(void(^)(UIImage*))completion;
#end
As you can see, I'm trying to make something like that in client code:
[[[ImageGetter alloc] init] requestImageInView:_viewController.view withCompletionBlock:^(UIImage *image) {
// do stuff with taken image
}];
Here is how I've implemented ImageGetter:
-(void) requestImageInView:(UIView*)view withCompletionBlock:(ImageTakenCallback)completion
{
completionBlock = [completion copy];
picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
[view addSubview:picker.view];
}
- (void)imagePickerController:(UIImagePickerController *)picker_
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
[picker.view removeFromSuperview];
picker = nil;
completionBlock(image);
}
The problem is since I'm using ARC, the instance of ImageGetter is deallocated instantly after call for -requestImage..., so the weak delegate of picker becomes nil.
Which are common ways to resolve such a issue?
I can see some ways, however, none of them seems to be quite right:
retain ImageGetter from client code, for example, assign it to a strong property. The problems here are: I wont be able to release it by setting this property to nil right after I get image, because this will mean setting retain count of object to 0 while executing the method of this object. Also, I don't want unnecessary properties (well, it is not a big problem, but nevertheless).
disable ARC for ImageGetter and manually retain at start itself and release after sending image to callback.
make static manager ImageGetterManager, which will have method requestImage..., it will create ImageGetter instances, retain them, redirect the requestImage... call, get callbacks from them and release. That seems the most consistent way, but is not it a bit complex for such a little code?
So how can I build such a class?
You can handle that within the ImageGetter class by creating and releasing a "self-reference".
In a class extension in the implementation file, declare a property
#interface ImageGetter ()
#property (strong, nonatomic) id selfRef;
#end
In requestImageInView:, set self.selfRef = self to prevent deallocation.
In the completion method, set self.selfRef = nil.
Remark: Actually you can manage the retain count even with ARC:
CFRetain((__bridge CFTypeRef)(self)); // Increases the retain count to prevent deallocation.
CFRelease((__bridge CFTypeRef)(self)); // Decreases the retain count.
But I am not sure if this is considered "good programming" with ARC or not.
Any feedback is welcome!
If this issue is introduced when switching to ARC, I should just go for option 1, and define it as a strong property.
However the behaviour is a bit different than you described for option 1: Setting the property to nil, does NOT mean the object is instantly released, it will just cause a decrement of the retaincount. ARC will handle that fine, the object will be released as soon as all referenced objects have 'released' it.
You can use the following strategy:
ImageGetter* imgGetter = [[ImageGetter alloc] init];
[imgGetter requestImageInView:_viewController.view withCompletionBlock:^(UIImage *image) {
// do stuff with taken image
[imgGetter releaseCompletionBlock]; // With this line, the completion block will retain automatically imgGetter, which will be released after the release of the completionBlock.
}];
Inside your ImageGetter implementation class, create a method that you can call inside the block like this.
-(void) releaseCompletionBlock
{
completionBlock = nil;
}

iOS App Crashes while releasing a retained property

I have a question. There may be a very simple solution to this question but I am not able to figure it out yet. If I use a property say #property(nonatomic, retain)UIView *mainView.
Now I synthesize it in .m file and release it in the dealloc method as following:
- (void)dealloc {
[mainView release], mainView = nil;
[super dealloc];
}
Then in my viewDidLoad, I'm allocating it and adding it as the subview of my self.view like following:
- (void) viewDidLoad {
mainView = [[UIView alloc] init];
.
.
.
[self.view addSubView: mainView];
}
Now I understand that at this point my mainView would have 3 reference counts (one from alloc, one because it's a retained property, and the third one when I added it to self.view), its parent controller would own it too.
Now, my question is if after adding my view to self.view, I release my mainView using
[mainView release];
My app crashes when I go back to the previous view as I am sending release to already deallocated object. Now my question is how am I overreleasing my view here. what am I missing because when I use following code it works fine and no crashes occur.
- (void) viewDidLoad {
UIView *newView = [[UIView alloc] init];
self.mainView = newView;
[newView release];
.
.
.
[self.view addSubView: mainView];
}
I know why this second viewDidLoad method works but what I dont know is why first one fails, I am supposed to release my view after adding it to self.view. Right?
NOTE: I understand that in the first viewDidLoad, I can use autorelease method to release the view that is being assigned to the ivar and it wont crash but the whole point is I am trying to reduce the use of autorelease as much as possible. And I am not using ARC at all
I would really appreciate the explanation and suggestions.
From your question:
Now i understand that at this point my mainView would have 3 reference
counts (one from alloc, one coz its a retained property and the third
one when i added it to self.view)
You didn't assign through the property but assigned directly to the instance variable, so there was no retain; only in ARC does assigning to the instance variable retain the value. So, do not perform the manual release.
In order for your #property to retain the mainView, you should use it as self.mainView and not just mainView. If you use the latter alone, it will not retain it. Basically if you call self.mainView = ... it is calling a setter method for mainView which does a [mainView retain]; internally. When you are directly assigning it, it wont execute this setter and retain will not be executed.
You should try it like this,
self.mainView = [[[UIView alloc] init] autorelease];
[self.view addSubView:self.mainView];
or as shown in your question.
UIView *newView = [UIView alloc] init];
self.mainView = newView;
[newView release];
[self.view addSubView:self.mainView];
You can also try using ARC for your project. Your code will look like this in ARC,
self.mainView = [[UIView alloc] init];
[self.view addSubView:self.mainView];
Check the documentation for more details.
In your first viewDidLoad method you are not referring to self.mainView only mainView thats why its not retained, in order to retain property work you have to set mainView using self.mainView!

Non retained objects: when are they released?

Inside an initialization method, I have the following code
- (id)init {
self = [super init];
if (self) {
UIButton *tempButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
tempButton.frame = CGRectMake(0,0,300,44);
// some custom code...
self.myButton = tempButton;
}
return self;
}
Where myButton is a retained property.
I know that, for what concerns memory management rules, this method equals this other:
- (id)init {
self = [super init];
if (self) {
UIButton *tempButton = [[UIButton alloc] initWithFrame:CGRectMake(0,0,300,44)];
// some custom code...
self.myButton = tempButton;
[tempButton release];
}
return self;
}
But in this case I need to use the first "version" because the buttonType property is readonly and I cannot change it after having the button initalized.
Since I find myself using the "non init-release" version in multiple methods all over my application, and for several object (most of them are NSString), my question is: not counting in this case the assignment to the property which retains the object, when the tempButton object will be released? Maybe at the end of the method/if statement? Or will the first "version" lead to an increased memory usage, since the object is not being released right away but after a certain amount of time?
I think you're a bit confused here: in both of your snippets, you create a tempButton object, but then you're assigning it to self.myButton. At that point, both tempButton and self.myButton are pointers to the same object. Now, presumably the myButton #property you're using is a strong property, so by assigning tempButton to it, you increase its retain count, and therefore in either version of the code it would have a retain count of +1 at the end, and would not be dealloc'ed.
If, hypothetically, myButton wasn't a strong property, then there would be an error in your code, and in both cases tempButton would be prematurely released and dealloc'ed. Here's what would happen in the two cases:
In your first version, since you're getting tempButton comes from something other than an init or copy method, it gets a retain count of +1, but is autoreleased. At the end of the current iteration of the run loop, the autorelease would kick in, bringing its retain count to 0 and causing it to be dealloc'ed.
In the second version, you first get a tempButton with a retain count of 1 because it's coming from an init method. But later on you explicitly release it, bringing its retain count to 0, at which point it is immediately dealloc'ed.
the non-init method is exactly the same as:
UIButton *tempButton = [[[UIButton alloc] initWithFrame:CGRectMake(0,0,300,44)] autorelease];
so the idea is to understand more about how the auto release pool works, its very useful most of the time but u need to understand how it works incase u will use the object later on in the app.
and to note something, when u add the temp button to ur view that view will retain it, and will release it when its removed from it, u can use instruments and check the retain count of the object if u wish to view how release/retain is going on if u want to see it in action.

Why myInstance = nil instead of self.myInstance = nil?

Why would I use (inside my dealloc method)?
[myInstance release] instead of [self.myInstance release]
myInstance = nil instead of self.myInstance = nil
Although we use self.myInstance = [[[AClass alloc] init] autorelease] instead of myInstance = [[[AClass alloc] init] autorelease]?
Those practices are from numerous examples I see on the web.
1) [myInstance release] instead of [self.myInstance release]
prefer the former.
the returned value of self.myInstance is defined by implementation when a subclass has overridden the method myInstance. you're not interested in the behaviour of the interface of a constructed object during dealloc (since a subclass may override and return something other than your ivar).
what you are interested in dealloc is releasing the references you own before your object is destroyed. if the subclass has overridden myInstance, then it could:
a) return an ivar (declared in the subclass) that's already been released
or
b) the implementation of the override may return a newly created autoreleased object
either a or b could lead to an over-release and a crash (assuming everything else is correctly retained/released). this also suggests why you should assign nil to the ivar after releasing it.
this is also a classic example of how to trigger object resurrection. object resurrection occurs when an implementation of the getter/setter you call recreates its state after it's already been deallocated. the least offensive side-effect would cause a harmless leak.
2) myInstance = nil instead of self.myInstance = nil
again, prefer the former.
a formal response would look much like the response to #1 -- the rationale, side-effects and dangers apply here as well.
the safest way to handle this is to access the ivar directly:
[myInstance release], myInstance = nil;
because there may be really nasty side-effects (crashes, leaks, resurrection) which may be difficult to reproduce.
these dangers may be easily avoided and your code will be far easier to maintain. on the other hand, if people encounter the side-effects when using your programs, they will probably avoid (re)using it wherever they can.
good luck
Calling self.myInstance = uses the auto generated setter method. Calling [self.myInstance release]; calls release on the object returned by your getter method. It all depends on how your properties were set up (retain, assign?). There is no necessarily right or wrong answer to your question, since it all depends on the property in question. I suggest you read up on Objective C properties to get a better feel for this kind of thing.
And, unless myInstance was declared with assign, you wouldn't want to call self.myInstance = [[AClass alloc] init] You'd be much better off with self.myInstance = [[[AClass alloc] init] autorelease]
Note that using
myInstance = nil
instead of
self.myInstance = nil
Is incorrect (in the context of say a viewDidUnload method in a UIViewController subclass) if myInstance is a retain property, since if myInstance points to an object, it will be leaked!
This depends on a property that you defined in interface. For example if you define retain property:
#property (nonatomic, retain) NSObject *property;
then you may use just self.property = nil; in dealloc method, because it equals to:
[property release]; // releases previous property
property = [nil retain]; // [nil retain] returns just nil
The very same thing with self.property = [[A alloc] init];. This equals to
[property release]; // releases previous property
property = [[[A alloc] init] retain];
in case of property = [[A alloc] init]; property won't be retained.
Here's a full properties guide form Apple.
Actually using
self.myInstance = [[AClass alloc] init];
will lead in a memory leak, cause self.myInstance is using setter methods which leads in retain +1 along with alloc/init retain +1. So you'll get a retain count +2;
... = self.myInstance
and
self.myInstance = ...
are actually subroutine or method calls to getters and setters, which depending on how you define these subroutines, or have Objective C Properties create them, could do almost anything.
If the case of retain properties, the subroutines might play with the retain counts. If you do your own getters and setters, you could have them control the lights in your house, turning them on for none zero sets and turning the lights out when setting something to zero or nil. There doesn't even need to be a backing variable named "instance" which could be set by:
instance = ...

Resources