Retrieving the retain count for a CGImageRef object? - iphone

While you can release a reference to a CGImageRef object using "CGImageRelease", which, according to the SDK this "decrements the retain count of a bitmap image", is there a way to inspect the current retain count for a CGImageRef instance? [cgImageRef retainCount] isn't valid since CGImageRef isn't a valid receiver of the retainCount message.
In other words, during dealloc within a class that renders an EAGLContext, I want to make sure any outstanding references to CGImageRef objects are released but I obviously don't want to call CGImageRelease(someCGImageRef) if its retain count is already 0. I've found in practice that just checking to see if the image ref is nil isn't consistent with current retain count values.
Is it a best practice to simply set the CGImageRef instance to nil after you're done with it and you've already released it so that a check for (someCGImageRef == nil) lets you know if there is an outstanding reference to it?
Thanks

If I read the docs correctly, CGImageRelease is like CFRelease except that it handles NULL differently. That means CFGetRetainCount should work as long as cgImageRef is not NULL.
Okay, so I read the rest of your question after that. You shouldn't be calling CFGetRetainCount on an object that may already have a retainCount of 0, since by then the object is already destroyed. Instead, set it to NULL.
(NULL and nil are equivalent, but nil is for Objective-C objects. CGImageRef isn't one of those, so you should probably use NULL to avoid confusing yourself later.)

Related

Objective-C pointers/memory management question

I am testing the following code below. ffv is declared in the interface file.
ffv = [[FullFunctionView alloc] initWithFrame:self.view.bounds];
NSLog(#"%i", [ffv retainCount]); // prints 1
[self.view insertSubview:ffv belowSubview:switchViewsBtn];
NSLog(#"%i", [ffv retainCount]); // prints 2
[ffv release]; // you can release it now since the view has ownership of ffv
NSLog(#"%i", [ffv retainCount]); // prints 1
if (ffv == nil)
NSLog(#"ffv is nil");
// "ffv is nil" is not printed
[ffv testMethod]; // "test method called" is printed
this is my [ffv testMethod] implementation
- (void)testMethod
{
NSLog(#"test method called");
}
What I deduce in this case is that even if you release an object with retain count 2, you lose ownership of that object however, the reference is still kept.
Now, my question are:
Is my deduction correct?
Is there anything else important that can be deduced from this?
What are the complications caused by still keeping (using) ffv and calling methods from ffv? (My opinion is that this is ok since the view will always own ffv and won't release it until someone calls viewDidUnload. And as long as I don't pass ffv's reference to other objects.)
There are a couple of problems with using ffv after you have released it and it's only retained by your view controller's view.
1) It introduces a potential for future bugs, because later you might not remember that ffv is otherwise not retained. When you release the view (e.g. by replacing it with another view), you have a dangling pointer that you still hold a reference to.
2) In the special case of a UIViewController the view could be released at any time (you usually never call viewDidUnload yourself). The default behavior of UIViewController, when receiving a memory warning and the view is currently not visible, is to release the view, so unless you set the reference to nil in viewDidUnload, you have a dangling pointer again, even though you never explicitly released the view yourself.
1) Is my deduction correct?
Your deduction is correct. The Memory Management Programming Guide explains that each object has one or many owners. You own any object you create using any method starting with alloc, new, copy, or mutableCopy. You can also take ownership of an object using retain. When you're done with an object, you must relinquish ownership using release or autorelease.
Releasing the object doesn't change the value of any variables that reference that object. Your variable contains the object's memory address until you reassign it, no matter what retain count the object has. Even if the object's retain count goes to zero, causing the object to get deallocated, your variable will still point at that same address. If you try to access the object after it's been deallocated, your app will normally crash with EXC_BAD_ACCESS. This is a common memory management bug.
2) Is there anything else important that can be deduced from this?
Nothing comes to mind.
3) What are the complications caused by still keeping (using) ffv and calling methods from ffv? (My opinion is that this is ok since the view will always own ffv and won't release it until someone calls viewDidUnload. And as long as I don't pass ffv's reference to other objects.)
When you call release, you are telling the Objective C runtime that you no longer require access to the object. While there may be many cases like this one in which you know the object will still exist, in practice you really shouldn't access an object after calling release. You'd just be tempting fate and setting yourself up for future bugs.
I personally don't like peppering my code with release statements, because I don't trust myself to remember them 100% of the time. Instead, I prefer to autorelease my variables as soon as I allocate them like this:
ffv = [[[FullFunctionView alloc] initWithFrame:self.view.bounds] autorelease];
This guarantees that ffv will exist at least until the end of the method. It will get released shortly thereafter, typically before the next iteration of the run loop. (In theory this could consume excessive memory if you're allocating a large number of temporary objects in a tight loop, but in practice I've never encountered this case. If I ever do, it will be easy to optimize.)
The object is not deallocated until the retain count goes to 0. As long as it's not deallocated, you can keep using it without trouble. By retaining it you ensure that it won't be deallocated under your feet; however, if you retain another object that you know retains the first object, you can get away with this form of "indirect retaining". Don't complain when you move things around later and things start breaking, though.
if (ffv == nil)
NSLog(#"ffv is nil");
// "ffv is nil" is not printed
That's correct, releasing an object does not set the pointer to nil even if it is dealloced at that time. Good practice is to always set your pointer to nil after you release it.
You are correct to say that after you released it, it wasn't dealloced because the view still had a retain on it. But that's not how you should be thinking about it. If you want to use that object and you want it to be alive, retain it. Doesn't matter who else is retaining it. Your object has nothing to do with those other objects. You want it, retain it. You're done with it, release it and set your pointers to nil. If you don't set it to nil and everyone else also released it, you will have a dangling pointer to an object that was dealloced, and that will cause you a crash and much grievance.
so this:
[ffv release]; // you can release it now since the view has ownership of ffv
ffv = nil; // you released it, so that means you don't want it anymore, so set the pointer to nil
if you still want to use it, don't release it until you're done with it.
Well, I'm not sure 'losing' ownership is the right term. In Objective-C you have to carefully marshal your ownership of the object. If you create or retain an object, you are responsible for releasing it (either directly or via an autorelease pool). When you call release however, you don't lose a reference to the object, if something else has retained it, it will still be in memory, and your pointer will still potentially point to it.
You have a pointer ffv which is just a pointer to some memory, and you have the object which is created in the first line that ffv points to.
By calling release, you are stating that you no longer require the ponter ffv to point to a valid object, that in this context you would be happy for the object to be deallocated. The pointer still points to that bit of memory, and it is still there because its retain count was increased by assigning it to the view.
The line [ffv testMethod] is in danger of not working, as it follows the release and may not point to a valid object. It only works because something else is keeping it alive. ffv still has the same address value that it had when it was first assigned.
So in order:
Your deduction is correct.
Not really.
You shouldn't use ffv after the release call. You have no guarantee that the object is going to be there for you.
These are pointers we are using here, not references like you find in Java or C#. You have to marshal your ownership of the object, you create it, have some pointers to it and by careful management of retain and release calls you keep it in memory for as long as you need it.

What happens if you try to release an object that has been released?

What if I have an object, say NSIndexPath in which before I do a copy I always release it first?
Is it possible to have a memory count under 0?
I am doing this to prevent memory leaks.. is this a good way?
//global already has some value before in here or it doesn't have a value.. I want to update
//this with a new value (I no longer care to the old pointer)
[global release]
global = [indexPath copy];
Don't. When the retain count reaches 0, your object will be dealloc'ed and its pointer will become invalid, so using it again will cause unpredictable results (namely crashing).
You should read through Apple's Memory Management Guide.
This is the fundamental rule:
You only release or autorelease objects you own. You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message.
You use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (specifically: when the used autorelease pool receives a drain message).
Update:
As Josh pointed out, the one case you need to consider is when global and indexPath are the same. In that case, you would still "need" the pointer (to perform the copy), so you either autorelease (instead of releasing) or you use a temporary variable to handle that.
What you are doing is essentially correct, so long as global either has an old value that you no longer need or is nil. If it is one of a class's ivars, it will be nil when an instance of the class is created. The one catch is that if the new indexPath happens to be the same object as the one that's already in global, you will have over-released and you will crash.
// global points to object at 0x8BADFOOD
// indexPath also happens to be 0x8BADFOOD; for some reason, it
// hasn't changed since last time. This _can_ happen.
[global release]; // object at 0x8BADFOOD is deallocated
global = [indexPath copy]; // indexPath no longer valid!
// Crash! Bang! Boom!
The way to avoid this is to use a temp variable.
When you declare a property as copy and synthesize that property, the setter method that is created looks essentially like this, and you can do the same thing:
- (void)setMyFloozit:(Floozit *)newFloozit {
// Copy first in case newFloozit and myFloozit are for
// some reason the same object
// Take ownership of a copy of newFloozit
Floozit * tmp = [newFloozit copy];
// We no longer need old value of myFloozit, so we release it.
[myFloozit release];
// tmp contains a value that we own, we just need to assign
// it to the correct name.
myFloozit = tmp;
}
This could be made slightly better by checking first to see whether newFloozit and myFloozit are the same, and doing nothing if they are.

Autoreleasing object returned from NSMutableArray

When a method returns an object that is taken from and NSMutableArray does the object must be autoreleased? Check the following method. Also should I autorelease the nil value?
-(NSObject*)getElementByID:(NSString*)ID{
for(int i=0;i<[elements count];i++){
NSObject *element = (NSObject*) [elements objectAtIndex:i];
if([element.key isEqualToString:ID]){
return [element autorelease];
}
}
return nil;
}
You must not autorelease element because you are not an owner of it (you have not put a retain on it). You would have become an owner of it if you acquired it using alloc, new or retain. Since you acquired this object calling objectAtIndex:, you do not own it. See Three Magic Words. Calling autorelease here will cause a crash later do to over-release.
Your method name is incorrect and breaks KVC. A method that begins with get must take a pointer that will be updated with the result. This should be elementForID:. As noted above with the three magic words, naming in ObjC is very important to writing stable code
As a side note, it is traditional to use id is most cases rather than NSObject*. They mean slightly different things, but typically id is correct.
You never need to do any memory management related things to nil. So, no, you should not send autorelease to nil.
You also should not need to send autorelease to the element object that you are returning from your elements array. That object you are returning will remain in memory by virtue of elements itself having retained it. If the calling method would like to retain the value that you return, it may. But if that calling method only uses the returned value within its own scope, it is safe for it to do so without retaining it.

Objective C, Memory Management

1) What is the reason for the use of retain?
For example, in a setter method:
- (void) setCount: (int) input {
[intCount autorelease];
intCount = [input retain];
}
2) the autorelease-Method: Is it deleting an old object or preparing the new one?
3) Why the retain-method is called at the input-object?
Would
intCount = input;
be wrong?
And why?
Retain is used to increment the retainCount of an object. NSObjects have a property called retainCount which maintains a count on the number of references that are currently held on an object. When the retainCount of an object reaches 0, the object can be released from memory. Effectively this prevents an object from being released from memory if it's still in use elsewhere.
The autorelease method does not delete an old object and does not prepare the new object. It is effectively a pre-emptive call to release the object (autorelease is much more complicated than that and you should read up on it in the Memory Management Guide.)
In your case intCount = input wouldn't be wrong because you're working with a primative. However if input were an object then you'd need to be calling retain on it. In fact you don't even need to be writing your own getters/setters for primatives (or objects), but instead should be using Declared Properties. In fact you're almost always better off using Declared Properties and if you do want to roll your own, get to know the pitfalls of doing so first.
I recommend you read this. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
The answers to your questions have been answered fairly well so let me just add that if you can use garbage collection you should. It makes everything so much easier. It isn't a panacea and you still should learn to use the retain/release mechanism but unless you are dealing in some high volume memory calls, creating and deleting lots of objects, then just use garbage collection.
It can be found under Project | Edit Project Settings | Build
Then just search for "garbage" and you'll see it.
If you are doing iOS development and cannot use garbage collection I apologize for giving unhelpful information but it still stands for non-iOS development.
To answer ur question specifically:
1). the use of retain is to declare the ownership of an object. In this case, intCount retains the ownership of input, in case the input got released somewhere else, u can still use the intCount.
2). the autorelease of intCount is to relinquish the ownership of the old value. That avoid the memory leak of the old value. If u don't release the old value, and u assign a new value to this pointer, the old object will always be there and never got released, which will cause the memory leak.
3). if u don't retain the input, and the parameter of input got released somewhere else. then if nowhere else retain this object, it will get freed. So u can't use intCount as well. That's why u need to retain it or copy it.
But i think if u do intCount = input; it should be fine. Because int is not an object, it's just a type. So I think the whole method is okay to be written like this:
- (void) setCount: (int) input {
intCount = input;
}
But if its a pointer, u should not assign the new value to the old one directly.

Is there an automatic release with setTitle (UIButton class)?

As everyone knows, setTitle automatically retains the string passed as a parameter. When the button caption needs to be changed, I guess that it is necesary to release the current (old) string before setting the new one. I wonder what is the most elegant way to dot it.
See my code sample (here, getPlayerHandFromGame method produces autoreleased strings which are retained when setTitle is invoked):
colourString = [pGame getPlayerHandFromGame:1 withColour:COLOUR_HEARTS];
// Split colourString into array of strings if not null.
if ([colourString length] != 0) {
listCards = [colourString componentsSeparatedByString:#" "];
for (cardCounterSameColour = 1; cardCounterSameColour <= [listCards count]; cardCounterSameColour ++) {
currentCardButton = [self buttonCardNumber:cardCounter];
// Objects are numbered from 0 in the array
[currentCardButton setTitle:[listCards objectAtIndex:cardCounterSameColour-1] forState:UIControlStateNormal];
cardCounter ++;
}
}
This portion of code will be called several times since the button caption will be updated several times. I guess that before setting the title, I should do something like this:
[currentCardButton titleForState:UIControlStateNormal release]
in order to release the string which will not be used anymore (titleForState returns a pointer to the NSString).
Is that the right way to avoid that the device memory gets loaded with unused strings ?
Many thanks,
Apple92
Any class that retains a value set on one of its properties is also responsible for releasing the old value when that property's value gets changed again. Don't worry about it.
As everyone knows, setTitle automatically retains the string passed as a parameter.
Really? I don't know it. In fact, I'll bet a pint of beer that it doesn't retain the string, but copies it.
Granted, for an NSString, -copy is probably implemented as doing a retain and returning self, but if you pass it an NSMutableString, a genuine copy will occur.
I guess that it is necesary to release the current (old) string before setting the new one.
Guess again, sucker!
Or less facetiously: any object is responsible for managing the ownership of other objects it wantsa to keep hold of. Once you have passed the title in setTitle: you do not need to worry about how the object disposes of it once it gets a new one.
Consider the code:
[currentCardButton titleForState:UIControlStateNormal]
and apply the memory management rules to the return result.
Did you obtain it with alloc, new or copy? No. Did you retain it? No (remember we are talking about the object passed back by the method,not the object you originally gave it). Therefore, you must not release it.
Take a look at the object ownership convention:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-BEHDEDDB
Every class should follow these rules (Apple's does it), so in order to them you dont have to worry because you haven't done a alloc/retain in your class, and the button will retain it for it's internal use.