How to release IBOutlet defined as property?
Asked Answered
H

7

2

sorry for this question, but I searched it and I didn't find an answer for that case.

I'm studying memory management for iOS and I understood, or I think so, the view lifecycle. But now I have a question on a IBOutlet (tat is linked to a UIImageView in my xib file). I have a class like this:

@interface MyClass : UIViewController 

@property (nonatomic, retain) IBOutlet UIImageView *myImage;

The question is: how can I release myImage? Is this ok?

- (void)dealloc {
    self.myImage = nil;
    [super dealloc];
}

- (void)viewDidUnload {
    [super viewDidUnload];
    self.myImage = nil;
}

Can someone explain why can't I call the release method on myView (if you had some lik it is good too!)?

Thanks in advance!

Hudis answered 14/2, 2012 at 17:18 Comment(0)
G
1

In general, you don't call release on a property, you would call it on the corresponding ivar. This is my standard way to handle IBOutlet properties:

@interface MyClass

@property (nonatomic, retain) IBOutlet UIImageView *myImageView;
@property (nonatomic, retain) IBOutlet UILabel *myLabel;

@end


@implementation MyClass

@synthesize myImageView = _myImageView;
@synthesize myLabel = _myLabel;


- (void)dealloc {

    [_myImageView release];
    [_myLabel release];

    [super dealloc];
}

@end
Gouveia answered 14/2, 2012 at 17:27 Comment(8)
If I try to use your code, xCode gives me an errore on the line "[_myImageView release]"... This is why I wrote a question, I can't understand why.Hudis
You must have ARC enabled then.Gouveia
It's impossible, I compiled it for iPAD 4.3 (in the simulator)Hudis
"This class is not key value coding-compliant for the key _sectionImageView."Hudis
I don't know why, but today after a "Clean" at my project your code works perfectly! Thanks! Another related questione: and if I have another object instead of a IBOutlet (like a NSArray) can I use your code again? Is it correct? What is the convention in this case? Thanks :)Hudis
Yes, my code will work fine for any properties that you need to retain. You may not want to call self.myArray = nil in viewDidUnload though, as other properties are usually kept around for longer.Gouveia
I. This won't work anymore in iOS6, cause viewDidUnload deprecated. Another recommended way?Mlle
@Mlle Use ARC now, there's no point doing manual memory management anymore. Or if you must do it manually, I've updated my answer to reflect API changes.Gouveia
M
3

IBOutlet have nothing to deal with memory management.

But because it is retain property, so you need to release it in dealloc.

So your code is correct.

Menton answered 14/2, 2012 at 23:7 Comment(0)
F
1

What you are doing is correct, and you generally shoudnt call release on the properties, since setting to nil does that already, however if you have a backing ivar to your property you can call release on that...

Fail answered 14/2, 2012 at 17:26 Comment(1)
Thanks for the answer, can you give me an URL to a documente that explain this? Because it seems to be right, but I can't understand why :)Hudis
A
1

There's a property and an instance variable behind the property. They both are called myImage, I presume (or you wouldn't be asking this question). You can free the instance in two ways - either release and nil the ivar, or just nil the property.

The compiler-generated setter for retained properties (like this one) works as following: release the currently held object reference (if any), assign the new value to the underlying ivar, retain it (if not nil). So when you assign nil to a property, it has the effect of releasing the current value and replacing it with nil.

To do that, use

self.myImage = nil; //invoke property setter behind the scenes

To free an ivar, use

[myImage release];
myImage = nil;

This is functionally equivalent to the code above. Marginally faster. The thing you should be clear about is the distinction between properties and backing ivars. For that very reason, some people make a point of assigning different names to them, and synthesizing like this:

@synthesize MyImage = _MyImage;
Anatole answered 14/2, 2012 at 17:26 Comment(2)
Maybe you're overreleasing. Chances are your ivar points at a zombie object - one that was released at some point already. Read up on the NSZombie setting, enable it and see if that's case.Anatole
If that's a compilation error (as opposed to a run-time error) - what type is myImage? What's the base class?Anatole
G
1

In general, you don't call release on a property, you would call it on the corresponding ivar. This is my standard way to handle IBOutlet properties:

@interface MyClass

@property (nonatomic, retain) IBOutlet UIImageView *myImageView;
@property (nonatomic, retain) IBOutlet UILabel *myLabel;

@end


@implementation MyClass

@synthesize myImageView = _myImageView;
@synthesize myLabel = _myLabel;


- (void)dealloc {

    [_myImageView release];
    [_myLabel release];

    [super dealloc];
}

@end
Gouveia answered 14/2, 2012 at 17:27 Comment(8)
If I try to use your code, xCode gives me an errore on the line "[_myImageView release]"... This is why I wrote a question, I can't understand why.Hudis
You must have ARC enabled then.Gouveia
It's impossible, I compiled it for iPAD 4.3 (in the simulator)Hudis
"This class is not key value coding-compliant for the key _sectionImageView."Hudis
I don't know why, but today after a "Clean" at my project your code works perfectly! Thanks! Another related questione: and if I have another object instead of a IBOutlet (like a NSArray) can I use your code again? Is it correct? What is the convention in this case? Thanks :)Hudis
Yes, my code will work fine for any properties that you need to retain. You may not want to call self.myArray = nil in viewDidUnload though, as other properties are usually kept around for longer.Gouveia
I. This won't work anymore in iOS6, cause viewDidUnload deprecated. Another recommended way?Mlle
@Mlle Use ARC now, there's no point doing manual memory management anymore. Or if you must do it manually, I've updated my answer to reflect API changes.Gouveia
S
1

From Apple's documentation:

Legacy Patterns Prior to ARC, the rules for managing nib objects are different from those described above. How you manage the objects depends on the platform and on the memory model in use. Whichever platform you develop for, you should define outlets using the Objective-C declared properties feature.

The general form of the declaration should be:

@property (attributes) IBOutlet UserInterfaceElementClass *anOutlet;

Because the behavior of outlets depends on the platform, the actual declaration differs:

For iOS, you should use:

@property (nonatomic, retain) IBOutlet UserInterfaceElementClass *anOutlet;

For OS X, you should use:

@property (assign) IBOutlet UserInterfaceElementClass *anOutlet;

You should then either synthesize the corresponding accessor methods, or implement them according to the declaration, and (in iOS) release the corresponding variable in dealloc.

This pattern also works if you use the modern runtime and synthesize the instance variables, so it remains consistent across all situations.

Saturant answered 14/2, 2012 at 17:32 Comment(3)
This is exactly what I did, but xcode gave me an error while calling [anOutlet release] in my dealloc... And I can't understand why.Hudis
Fawk, that's really weird. I have a lot of code running like this. Double check for other possible issues. Good luck!Saturant
Could you post the error that you get when implementing this?Saturant
G
0

First of all: consider switching to ARC if you aren't supporting iOS versions prior to 4.0.

Secondly, the best practice of writing dealloc methods says not to invoke setters. Instead, expressly release and nil your outlets:

[myImage release], myImage = nil;

Finally, when chaining together de-initialization methods like viewDidUnload, always call super's implementation after you do your own work.

The reason we nil out outlets in viewDidUnload is because sometimes views are unloaded when the system is under memory pressure. Since these outlets can be recreated easily, implementing viewDidUnload is a way to help performance, and in extreme situations, prevent your app from being forcefully terminated.

The reason we release properties in dealloc is to prevent memory leaks. So even though these two methods can look quite similar, they serve somewhat different purposes.

Grouchy answered 14/2, 2012 at 17:28 Comment(5)
I know the benefits using iOS 5, but I have to support iOS4.. The problem is that the line [myImage release] gives me an error...Hudis
Even though ARC was introduced by the SDK that accompanied iOS 5, it is backwards-compatible to iOS 4, almost transparently. So it's quite possible you created the project with ARC enabled. If you get compiler errors complaining about calling release, it's practically certain you did.Grouchy
NO wait, ARC isn't active (I checked), and I call the release method hundreds of time in my code and it gives me error only in this case. So I think this isn't an ARC related error :)...Hudis
Fair enough, then. What's the exact error message you receive?Grouchy
"This class is not key value coding-compliant for the key _sectionImageView."Hudis
S
0

I don't really get what you mean by "why can't I call the release method on myView"

Your code seems correct to me but by convention I usually prefer to release the iVar directly for a retained property I usually synthesize my property like this :

@synthesize myImage = _myImage;

And then you I release the iVar in the dealloc method

- (void)dealloc {
     [_myImage release];
     [super dealloc];
}

Anywhere else in the Controller I just go for the getter and setter (the dot convention)

Your viewDidUnload is correct.

By the way, if you're using ARC just declare your IBOutlet as a weak pointer. It will be automatically released in low memory situations and reloaded as soon as your view is loaded back again.

Hope this will help ;)

Spectacular answered 14/2, 2012 at 17:35 Comment(1)
Thanks but this line gives me error... [_myImage release]. I thougt it was correct too, but it seems to be a mistake. I checked and I don't have ARC enabled (i'm using my app on iPad 4.3 in simulator)Hudis

© 2022 - 2024 — McMap. All rights reserved.