iPhone Memory Management - iphone

Hello Stackoverflow fellow family members!
I've got question regarding memory management in iPhone.
What I did understand was below method
-(void) dealloc
{
// something else to release whatever
// such as Object Created using keyword 'alloc'
// but also Object destroy here its retain value reaches iff 0
// if I do put here NSLog(#"%d", [obj retainCount]); and when it reaches
// not equal to 0 means failure with memory leak.
[super dealloc];
}
So am I understand right? or It is still alight even if retain count reachs > 0 here?
The reason I ask about this question because,
I checked with
NSLog(#"%d", obj.retainCount);
to check the retain count of the object and received value 3. So I tried to release here 3 times to make retainCount here equal to 0, but compiler gives me critical error.
Please, I'm new to the memory de-allocation and retain, release.
Object that I used was 'UIImageView' object and created another instance as,
UIImageView *imageView = //da da~ with UIImage
UIImageView *instance;
// at this point retain count was '1'
instance = imageView;
//[imageView retain];
// at this point retain count was '2'
[self.view addSubView: imageView];
// at this point retain count was '3'
[imageView release];// crashes
// at this point retain count was '2'
but if I do
// but if I add retain on the 'instance = imageView'
// such as
instance = imageView; // then
[imageView retain];
// works but still count is 2...
Thank You.

retainCount is not a reliable debugging-tool:
other objects might still hold references to obj
there are objects that you can't destroy (e.g. string constants)
objects are deallocated if released with a retain count of 1
What you should take care of instead:
balancing references you have with the right amount of release/autorelease
using the Analyzer
using Leaks

The normal process for overriding dealloc is to release any objects that have been previously retained (or alloc'ed) by this instance.
So if somewhere else in the object you have called an alloc or retain method your dealloc would look like:
-(void)someOtherMethod
{
UIImageView *imageView = //da da~ with UIImage
UIImageView *instance;
instance = imageView;
[instance retain];
}
-(void) dealloc
{
//release any retained objects here
[instance release]
[super dealloc];
}
Note that it doesn't matter if the release count hasn't dropped to zero after your particular release, that just means that some other bit of code has also retained the object memory (and that other bit of code will be responsible for releasing it).
Hope this helps.

That's not correct and you should rarely use retainCount. It does not have to be 0 at this point as other objects could have references to the objects you are releasing. What is important to do in dealloc is to release objects that you have ownership on. Which would be objects created with alloc or new etc.

Related

Allocating a property

Working on someone else's code. Came across a piece of code while analyzing the project
self.groupPicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0,260,320,216)];
self.groupPicker.delegate = self;
self.groupPicker.showsSelectionIndicator = YES;
[self.view addSubview:self.groupPicker];
Where groupPicker is a UIPicker property. When analyzing the project I encountered a potential leak warning in this case. I have also noticed that the groupPicker property is not being released in the dealloc method. Nor is _groupPicker released anywhere in the project. What should be done in this case?
Should I remove the UIPicker property and just declare a UIPicker variable instead.
Should I just release groupPicker like [_groupPicker release];
What would be the retain count of groupPicker as it is retained once in the .h file and again being allocated as shown in the above piece of code.
1) No, it is perfectly fine to have the property, the problem is that it is being over retained. When you alloc/init the retain count is 1, then you use the retained property which increases the retain count again. The retain count is now 2 and assuming you release the object in dealloc, you end up with a retain count of 1, i.e. a leaked object.
There are many ways you can handle the problem. I think the best way is to autorelease the object on initialization. Like so
self.groupPicker = [[[UIPickerView alloc] initWithFrame:CGRectMake(0,260,320,216)] autorelease];
2) Anything you retain should be released in dealloc, so in dealloc you should
- (void)dealloc {
[_groupPicker release];
[super dealloc];
}
Watch out! When you set a property like
self.property1 = x;
and the property1 is declared as retain, the previous object in the property1 is released and the new object (x) is retained. This is why doing this:
self.property1 = [[x alloc] init];
when property1 is declared as retain, will retain x twice. (one for init, one for setting the property)
The correct way is declaring the object, setting to the property and then releasing
object x = [[class alloc] init];
self.property1 = x;
[x release];
This way, you give the "responsability" of releasing the object x to the property holder.
While using ARC for iOS5+ applications should be preferred, if you don't want to do that just use autorelease after init method.
You should use ARC (Automatic Reference Counting)
to do so got to edit>refactor>convert to objective c ARC
Either assign the UIPickerView to _groupPicker (or whatever the instance variable is named), or use an autorelease on the value as you assign it.
(The problem is that assigning to a retained property causes a retain, and there's already a retain on the object from the alloc.)

iPhone alloc and release

i am new in ObjC and iPhone.
I downloaded an example of data sharing between multiple views. The basic approach is to create an data model object in the base UIApplication and get/set data from/to it. So in the init method i saw the following code:
- (id) init;
{
self.theAppDataObject = [[ExampleAppDataObject alloc] init];
[theAppDataObject release];
return [super init];
}
And after that, using delegate we can access this object.
id theDelegate = (id) [UIApplication sharedApplication].delegate;
ExampleAppDataObject* theDataObject;
theDataObject = (ExampleAppDataObject*) theDelegate.theAppDataObject;
So, my question is in the first code example. Why do we need to alloc memory for the theAppDataObject object, and immediately after that - release the object? Why don't we get nil when accessing this object later?
10x
I assume theAppDataObject is declared as #property (retain). Therefore, when setting the object by doing self.theAppDataObject (or [self setTheAppDataObject:]), this property will retain the ExampleAppDataObject. Therefore, you can release it afterwards.
When you alloc and init the ExampleAppDataObject, it's retain count goes up to 1. When you set the AppDataObject to this ExampleAppDataObject, it sends retain to it, so the retain count goes up to 2. You can then release your own ownership of the object; it won't get deallocated because theAppDataObject still has ownership.
If that makes sense.
That depends on how theAppDataObject property is defined.
If it provides a retaining setter-accessor the retain count of the appDataObject will flip to 2, one more than needed here.
So release one of it.
Better and more understandable way would be to write
if ( (self = [super init]) ) {
ExampleAppDataObject *myAppDataObject = [[ExampleAppDataObject alloc] init];
self.theAppDataObject = myAppDataObject;
[myAppDataObject release];
}
return self;
Iphone uses reference count based memory management model..See this tutorial first and then apple's technical documentation... theAppDataObject is a property (see the use of self. theAppDataObject) which should be retained for the above code to work..Any object which is retained should have a bonus plus 1 retain count...An object only gets released when its retain count gets to zero..
first things first: that code sample is terrible.
- (id) init
{
// assign self. super may return another address
self = [super init];
// then check for nil
if (self != nil) {
// then assign the ivar directly because you should
// not invoke methods of partially constructed objects
theAppDataObject = [[ExampleAppDataObject alloc] init];
}
// then return the address super returned
return self;
}
now for your questions:
Why do we need to alloc memory for the theAppDataObject object, and immediately after that - release the object?
self.theAppDataObject calls through the setter, which retains, copies, or assigns theAppDataObject. in this case, we could assume it is highly likely to be retained.
Why don't we get nil when accessing this object later?
release does not set a pointer to nil. it sends a message to the object which then decrements the retain count (in the typical case). what you might have expected in this case is an object which has been deallocated. that does not happen when the argument is retained because the reference count does not reach zero in the program you have shown. the object is still alive because it's been retained and the address of the object stored when the setter (self.theAppDataObject = arg) is called.

Custom UIButton Memory Management in dealloc

I am hoping to clarify the processes going on here.
I have created a subclass of UIButton whose init method looks like this:
- (id)initWithTitle:(NSString *)title frame:(CGRect)btnFrame {
self = [UIButton buttonWithType:UIButtonTypeCustom];
[self setTitle:title forState:UIControlStateNormal];
self.frame = btnFrame;
return self;
}
In my view controller I am creating one of these buttons and adding it as a subview:
myButton = [[CustomButton alloc] initWithTitle:#"Title" frame:someFrame];
[self.view addSubview:myButton];
In the view controller's dealloc method I log the retain count of my button:
- (void)dealloc {
NSLog(#"RC: %d", [myButton retainCount]); //RC = 2
[super dealloc];
NSLog(#"RC: %d", [myButton retainCount]); //RC = 1
}
The way I understand it, myButton is not actually retained, even though I invoked it using alloc, because in my subclass I created an autorelease button (using buttonWithType:).
In dealloc, does this mean that, when dealloc is called the superview releases the button and its retain count goes down to 1? The button has not yet been autoreleased?
Or do I need to get that retain count down to zero after calling [super dealloc]?
Cheers.
This deserves two answers.... one for the specific question and one for how memory is managed when the instance is replaced in -init (this one).
Initializers are an odd bird in the Objective-C memory management world. In effect, you are managing self. On entry, self is retained. On exit, you are expected to return either a retained object -- doesn't have to be the same object as self -- or nil.
So, breaking the standard idiom of [[[Foo alloc] init] autorelease] down:
id x = [Foo alloc]; // allocates instance with RC +1
x = [x init]; // RC is preserved, but x may differ
[x autorelease]; // RC -1 (sometime in future)
Note that all retain counts [RC] are expressed as deltas.
Thus, in the init method, you typically don't change the retain count of self at all!
However, if you want to return some other object, you need to release self and retain whatever you are going to return (whether allocated then or previously allocated somewhere else, say when an object is retrieved from a cache).
Specifically, with everything blown out into individual expressions because this answer is being overly pedantic:
- init {
[self release];
self = nil;
id newObject = [SomeClass alloc];
newObject = [newObject init];
if (newObject) {
self = newObject;
... initialize self here, if that is your fancy ...
}
return self;
}
This is more than a little bit tricky. I have summarized my answer in 5 parts:
Creating a custom init method that returns a different object
WARNING: beware of illegal memory access!
How to properly transfer ownership of the button to its parent view
Specific answers to specific questions
A suggestion for improvement
Part 1 : Creating a custom init method that returns a different object:
This is an example of a very special case, namely that the object returned from -initWithTitle:frame: is not the same "object" that was sent the message in the first place.
Normally speaking, the process goes like this:
instance = [Class alloc];
[instance init];
...
[instance release];
Of course, the alloc and init calls are usually grouped together into one line of code. The key thing to notice here is that the "object" (nothing more than an allocated block of memory at this point) which receives the call to init has already been allocated. If you return a different object (as in your example), you are responsible for releasing that original block of memory.
The next step would be to return a new object that has the proper retain count. Since you are using a factory method (+buttonWithType:), the resulting object has been autoreleased, and you must retain it to set the proper retain count.
Edit: A proper -init method should explicitly test to make sure that it is working with a properly initialized object before it does anything else with that object. This test was missing from my answer, but present in bbum's answer.
Here is how your init method should look:
- (id)initWithTitle:(NSString *)title frame:(CGRect)btnFrame {
[self release]; // discard the original "self"
self = [UIButton buttonWithType:UIButtonTypeCustom];
if (self == nil) { return nil; }
[self retain]; // set the proper retain count
[self setTitle:title forState:UIControlStateNormal];
self.frame = btnFrame;
return self;
}
Part 2: WARNING: beware of illegal memory access!
If you are allocating an instance of CustomButton, and then replacing it with an instance of UIButton, you could easily cause some very subtle memory errors. Let's say CustomButton has some ivars:
#class CustomButton : UIButton
{
int someVar;
int someOtherVar;
}
...
#end;
Now, when you replace the allocated CustomButton with an instance of UIButton in your custom init... method, you are returning a block of memory that is too small to hold a CustomButton, but your code will continue to treat this block of code as if it is a full-sized CustomButton. Uh oh.
For example, the following code is now very, very bad:
- (id)initWithTitle:(NSString *)title frame:(CGRect)btnFrame {
[self release]; // discard the original "self"
self = [UIButton buttonWithType:UIButtonTypeCustom];
[self retain]; // set the proper retain count
someOtherVar = 10; // danger, Will Robinson!
return self;
}
Part 3: How to properly transfer ownership of the button to its parent view:
As for your view controller's dealloc method, you will have to call [myButton release] if you have initialized the button as shown. This is to follow the rule that you must release anything that you alloc, retain or copy. A better way to deal with this issue is to let the controller's view take ownership of that button (which it does automatically when you add the button as a subview):
myButton = [[CustomButton alloc] initWithTitle:#"Title"
frame:someFrame]; // RC = 1
[self.view addSubview:myButton]; // RC = 2
[myButton release]; // RC = 1
Now, you never have to worry about releasing that button again. The view owns it, and will release it when the view itself is deallocated.
Part 4: Specific answers to specific questions:
Q: The way I understand it, myButton is not actually retained, even though I invoked it using alloc, because in my subclass I created an autorelease button (using buttonWithType:).
Correct.
Q: In dealloc, does this mean that, when dealloc is called the superview releases the button and its retain count goes down to 1? The button has not yet been autoreleased?
Also correct.
Q: Or do I need to get that retain count down to zero after calling [super dealloc]?
Sort of :) The retain count may or may not drop down to zero at the point when you log it. Autoreleased objects may still have a retain count of one, since they effectively belong to the autorelease pool for the current run loop. For that matter, the view itself may still belong to a window which has not yet been released. The only thing you really need to worry about is balancing out your own memory management. See Apple's memory management guide for details. From the point of view of your viewController, you have allocated the button once, so you must release it exactly once. When it comes to your custom init... method, things get a little bit trickier, but the principle is the same. A block of memory has been allocated, so it must be released (part 1), and, (part 2) init should return an object with a retain count of one (to be properly released later on).
Part 5: A suggestion for improvement:
You could avoid most of the custom initializer mess by simply creating your own factory method in the same spirit as the one provided by UIButton:
+ (id)buttonWithTitle:(NSString *)title frame:(CGRect)btnFrame {
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:title forState:UIControlStateNormal];
button.frame = btnFrame;
return button;
}
Note that this approach can still result in memory access errors as identified in part 2
First:
Do not call retainCount
The absolute retain count of an object is next to useless. There are always better ways to reason about memory management in your application.
Next:
Your initWithTitle:frame: method is allocating and returning an instance of UIButton, not an instance of the subclass. If that is what you want, there is no need for a subclass at all.
If you really want an instance of a subclass of UIButton, that is going to be more difficult. A quick google search and a read of the documentation indicates that UIButton really isn't intended to be subclassed.
I just tried:
#interface FooButton:UIButton
#end
#implementation FooButton
#end
FooButton *f = [FooButton buttonWithType: UIButtonTypeDetailDisclosure];
NSLog(#"%#", f);
And it printed:
<UIButton: 0x9d03fa0; frame = (0 0; 29 31); opaque = NO; layer = <CALayer: 0x9d040a0>>
I.e. the sole method to be used to create UIButton instances quite explicitly does not allocate via [self class]. You could go down the path of trying to initialize the instance by hand ala UIView or UIControl, but that is likely a lot of trouble.
What are you trying to do?

UIImage imageNamed not autoreleasing correctly

For some reason, the retain/release behavior in the following code has me completely baffled.
selectedImage = [UIImage imageNamed:#"icon_72.png"];
[selectedImage release];
This should break but does not. Why? I thought imageNamed autoreleased itself which means the release here is redundant and should break when the autorelease occurs.
Here are snippets relevant to selectedImage from the .h and .m files:
#property (nonatomic, readonly) UIImage *selectedImage;
#synthesize delegate, selectedImage, spacerBottom, currentIndex;
Other notes, this does break:
selectedImage = [UIImage imageNamed:#"icon_72.png"];
[selectedImage release];
[selectedImage release];
//objc[55541]: FREED(id): message release sent to freed object=0x59245b0
//Program received signal: “EXC_BAD_INSTRUCTION”.
As does this:
selectedImage = [UIImage imageNamed:#"icon_72.png"];
[selectedImage release];
[selectedImage autorelease];
//objc[55403]: FREED(id): message autorelease sent to freed object=0x59b54c0
//Program received signal: “EXC_BAD_INSTRUCTION”.
And so does the following:
selectedImage = [UIImage imageNamed:#"icon_72.png"];
[selectedImage autorelease];
[selectedImage release];
//objc[55264]: FREED(id): message release sent to freed object=0x592c9a0
//Program received signal: “EXC_BAD_INSTRUCTION”.
And so does this:
selectedImage = [UIImage imageNamed:#"icon_72.png"];
[selectedImage autorelease];
[selectedImage autorelease];
//objc[55635]: FREED(id): message release sent to freed object=0x5b305d0
//Program received signal: “EXC_BAD_INSTRUCTION”.
-imageNamed: returns an autoreleased image, which, as deanWombourne says, will be autoreleased at some time in the future (the exact time is undefined).
The reason it's not being autoreleased as early as you are perhaps used to is that -imageNamed also caches the image it returns. The cache is retaining the image.
So essentially, the retain cycle is something like this:
-imageNamed: called,
System allocs and init's an image -- retain count = 1;
System caches image -- retain count = 2;
System autoreleases image and returns to you -- retain count = 1; (theoretically, the image still has retain count of 2, because the auto release pool has not yet released it).
you call release on the image -- retain count should be 0 and the object should be deallocated.
At some point in the future (at the end of the run loop), the auto release pool should release the image, and will crash because you have over released it.
If you do not release it, the cache will continue to retain the image until it releases it, for instance when a memory warning occurs. So when you get an image using imageNamed, it doesn't get deallocated, until the cache is purged.
Hope this clears things up.
Odd and wierd, yes. But not completely inexplicable. this is what I think is happening.
You're correct; imageNamed: returns an autoreleased object. this means that it's going to get released sometime in the future so you calling release on it straight away won't cause an error - release isn't psychic, it doesn't know that an autorelease pool is also going to release it!
If you left your code running the autorelease pool will eventually try to release it again and then you will get the error you're expecting.
You've actually answered our own question - you say 'should break when the autorelease occurs' which is absolutely correct, when the autorelease occurs, it will break :)
The other examples break because you're forcing releases to happen by either calling them directly or doing enough stuff that the autorelase pool is triggered to run and calls release for you. (You can't predict when the autorelease pool will run, you can just know that at some point in your run loop, autoreleased things maight be released.)
You say that "This should break"
selectedImage = [UIImage imageNamed:#"icon_72.png"];
[selectedImage release];
You are wrong.
It probably would break if UIImage was an instance of the kind of Class you and i would write and learnt to write from our Cocoa books, but we didn't write it so we shouldn't guess at it's implementation.
How UIImage works is an implementation detail and not your concern. All you know is that you should be able to EXPECT it to work if you follow the rules, which i believe are now being referred to as NARC, and which you haven't done here. Nowhere are objects guaranteed to 'break' if you use them incorrectly. You cannot count on Objects being deallocated when you are thru with them - that isn't part of the memory management contract.
Not all of Apple's objects work like text book class/instances - in reality, objects may be cached, reused, recycled or not even be objects at all.
Don't worry about it, follow the rules.
When I create this category:
#implementation UIImage (ReleaseChecks)
+ (id)allocWithZone:(NSZone *)zone
{
id o = [super allocWithZone:(NSZone *)zone];
NSLog(#"Image post-ALLOC: 0x%x",
(unsigned int)o );
return o;
}
- (id)autorelease
{
NSLog(#"Image pre-AUTORELEASE: 0x%x; Retain Count %u",
(unsigned int)self,
(unsigned int)[self retainCount]
);
return [super autorelease];
}
- (void)release
{
NSLog(#"Image pre-RELEASE: 0x%x\n; Retain Count %u",
(unsigned int)self,
(unsigned int)[self retainCount]
);
[super release];
}
- (void)dealloc {
NSLog(#"Image pre-DEALLOC: 0x%x\n; Retain Count %u",
(unsigned int)self,
(unsigned int)[self retainCount]
);
[super dealloc];
}
It appears that -autorelease is not called when allocated with +imageNamed:.
However, when I have created a whole bunch of these with +imageNamed: and then later get a memory warning, I can see them all release and dealloc. This was tested on iPhone Simulator 4.0.

Two iPhone memory management questions

I have two questions.
1) Which of these will release ob?
- (void){
ClassOne *ob = [[ClassOne alloc] init]; // should I use autorelease here?
self.O = ob;
[ob release]; // is this correct ??
}
or
-(void)dealloc{
[O release]; // is this correct?
}
2) There are two classes, ClassOne and ClassTwo. A method in ClassTwo is:
- (void) takeParam:(ClassOne *pt) {
// something going here
}
and there is method in a third class
- (void) runIt {
ClassOne *ob = [[ClassOne alloc] init];
[classTwoOb takeParam:ob];
}
Where should I call release for the ClassOne object?
The -release method only reduces the retain count of the object in question. When the retain count reaches zero, the runtime will call -dealloc.
If at any time you send an alloc, copy, or retain message you must later call release or autorelease.
For more details see this excellent answer.
Number 1 is probably correct.
ClassOne *ob = [[ClassOne alloc] init]; // do i should use autorelease here ?
When you call [ClassOne alloc] you get an object with a retain count of 1 and you are responsible for the release.
self.O = ob;
Assuming self.O is a retain property and not an assign property, self.O/ob will have a retain count of 2.
[ob release];
Now self.O/ob will have a retain count of 1. This release matches up with the alloc. The remaining retain count is owned by self so you'll have to remember to release O when self is finished with it.
-(void)dealloc{
[O release]; // is this correct ??
}
Good. You remembered to release O. Now O will be fully released when self is dealloced. (Note: you should call [super dealloc] at the end of dealloc.)
- (void) runIt {
ClassOne *ob = [[ClassOne alloc] init];
[classTwoOb takeParam:ob];
}
You should release ob after calling takeParam:. Methods are responsible for retaining objects they want to keep. If takeParam: stores ob on classTwoOb, it should be retained before the method returns. If not, it shouldn't.
Use autorelease in methods that return objects that they have created. This gives the caller a chance to retain the object if it wants it, or not if doesn't need it for long. The exception to this is methods used to create objects, which should always be called alloc, new, or *copy*, and should return the object with a reference count of 1, making the caller responsible for the release.
To really learn Objective-C memory management, I recommend reading the Memory Management Programming Guide, especially the section on Memory Management Rules.