problem with nil and release? - iphone

i am using NSArray named as allAvailableServices .
first i initialize it and after wrote [allAvailableServices release];
then i checked the condition if(allAvailableServices).
it came as true!may i know the reason.
then i wrote
allAvailableServices = nil; and [allAvailableServices release];
after the above code if(allAvailableServices) came false.is there any problem that i wrote [allAvailableServices release]; after allAvailableServices = nil;
whenever allAvailableServices = nil i need to allocate new array.so if i didn't call [allAvailableServices release]; i think there is a memory problem.am i correct?
can any one provide me a best way to deal with it?

Release just reclaims the memory, but the pointer value isn't changed; it still contains a value, but it points to garbage.
This is why many people nil their pointer after releasing it:
[allAvailableServices release], allAvailableServices = nil;
In Objective-C, it is safe to send a message to nil, but sending a message to an object that has been released may cause the app to crash (usually with EXC_BAD_ACCESS)
Note, that I've released the object before setting it to nil. If you do it the other way around, you've lost the pointer to which you send the release message, and so you've leaked the object.

If you use accessors then you can directly set the values to nil, it calls the release and sets them to nil. A release decrements the reference count by 1 and if it reaches 0 the object is freed.
The memory still has some value if you do not set to nil and hence the problem in your if condition.
Cleaner way is to use accessors and call self.yourvariable = nil; .

Related

EXEC_BAD_ACCESS when i try to release a NSString that has an address allocated to it

I have a NSString that i try to release.
The problem is that in some cases i get EXC_BAD_ACCESS when i try to release it. The NSString has a address allocated to it (I can see in the bottom page that it has allocated memory at 0xABCDEF).
How can avoid this problem while realeasing when there is something there ?
You can release an object, but the pointer to it can still have a value. It's just that it's a garbage value (i.e. a dangling pointer).
That's why you see a lot of code such as:
[myObject release];
myObject nil;
which first releases the object and then sets the pointer to nil. That way any message sent to it will fail silently (because it's safe to send messages to nil objects in Objective-C) rather than crashing, as seems to be happening with your app.
Since you are checking the pointer, I suspect that you are doing something weird with memory management. Don't. Just follow the Memory Management Rules and only release the objects you own.
You've likely called [release] on an already released string. How are you allocating it? When an object is released, or autoreleased, it is not automatically set to nil (0x0).
[[NSString alloc] initWithSomething] requires a release call.
[NSString stringWithSomething] does not, as by convention, it is autoreleased.

iPhone object checking to release

I want to check if an object has some count or not Here is my testing code
NSMutableArray *array=[[NSMutableArray alloc]init];
if(array)
{
NSLog(#"hiiiiiii");
}
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
if(array)
{
NSLog(#"hiiiiiii");
}
Here in both cases i got same output as printed "hiiiiiii".
Can anyone tell me how will i check if my object need to release or already released.
I know that i should have track of my object's counters but i am at a stage where my code is too much complexed and i need help..
Please help..
ALso tell that how much memory leak is allowed by apple?
There is no way to check if you "should" release an object. Doing something like "if(object)" only checks the pointer to the object. It will return true even if the object it was pointing to was destroyed a long time ago. This is what happens in your second case. The object is destroyed when you call release, but the pointer is still pointing at something, so it returns true. It will only return false if the pointer is set to nil.
However, there is a simple set of rules for calling release. If you ever call "alloc", "new", "copy", "mutableCopy" or "retain" on object, you must always call "release" or "autorelease" on it. That will prevent any memory leaks.
Apple does not have a publicized amount of memory leaks allowed. It is always safest to eliminate any known memory leaks; plus, it will mean better performance for your customers.
In your second case you are releasing the NSMutableArray but still it store a non zero value although it's no longer for use (To call function OR fetch value).That the reason your if condition got true.
Just remember whenever you call release on any object, Do'nt forget to assign nil to that, So your second code should look like below.
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
array = nil;
if(array)
{
NSLog(#"hiiiiiii");
}
There is a simple rule of memory management in Object-C if your alloced or retain any object you must call release on that,
Read memory management Guide from Apple.

What's the difference between setting an object to nil vs. sending it a release message in dealloc

I have Object:
MyClass *obj= [[MyClass alloc] init];
What's the difference between:
[obj release]; // Only obj own this object.
and:
obj = nil;
Does iOS deallocs obj when i set obj = nil?
I have a pointer, sometime i set it point to an object, sometime do not. So, when i want release a pointer i must check is it nil?
This answer from the previous decade,
is now only of historic interest.
Today, you must use ARC.
Cheers
The very short answer is DO NOT just set it to nil. You must release it. Setting it to nil has no connection to releasing it. You must release it.
However it's worth remembering that if it is a property, then
self.obj = nil;
will in a fact release it for you. Of course, you must not forget the "self." part !!!!
Indeed,
self.obj = anyNewValue;
will indeed release the old memory for you, clean everything up magically and set it up with the new value. So, self.obj = nil is just a special case of that, it releases and cleanses everything and then just leaves it at nil.
So if anyone reading this is new and completely confused by memory,
You must release it, [x release] before setting it to nil x=nil
IF you are using a property, "don't forget the self. thingy"
IF you are using a property, you can just say self.x=nil or indeed self.x=somethingNew and it will take care of releasing and all that other complicated annoying stuff.
Eventually you will have to learn all the complicated stuff about release, autorelease, blah blah blah. But life is short, forget about it for now :-/
Hope it helps someone.
Again note, this post is now totally wrong. Use ARC.
Historic interest only.
Is It Necessary to Set Pointers to nil in Objective-C After release?
Release, Dealloc, and the Self reference
Setting an object nil versus release+realloc
Read the above. They answer your Q comprehensively
iOS does not support garbage collection, which means that doing obj = nil would result in a memory leak.
If you want automatic control over deallocation, you should do something like: obj = [[[NSObject alloc] init] autorelease] (you must NOT release it if you do that).
Autorelease would cause the object to be automatically released when the current NSRunloop event ends.
The NSRunloop automatically drains it's NSAutoReleasePool for each event iteration, which is usually very helpful.
Setting an object nil will create a memory leak(if you are taking ownership by alloc,retain or copy) because we are not having a pointer to that particular memory location.
so if you want to dealloc an object you have to take out all ownership of an object before making it nil by calling release method.
[obj release];
obj=nil;

EXC_BAD_ACCESS on iPhone when using "obj != nil

I've got a very simple line of code in Objective-C:
if ((selectedEntity != nil) && [selectedEntity isKindOfClass:[MobileEntity class]])
Occasionally and for no reason I can tell, the game crashes on this line of code with an EXC-BAD-ACCESS. It usually seems to be about the time when something gets removed from the playing field, so I'm guessing that what was the selectedEntity gets dealloc'd, then this results. Aside from being impossible to select exiting Entities (but who knows, maybe this isn't actually true in my code...), the fact that I am specifically checking to see if there is a selectedEntity before I access it means that I shouldn't be having any problems here. Objective-C is supposed to support Boolean short-citcuiting, but it appears to not be EDIT: looks like short-circuiting has nothing to do with the problem.
Also, I put a #try/#catch around this code block because I knew it was exploding every once in a while, but that appears to be ignored (I'm guessing EXC-BAD-ACCESS can't be caught).
So basically I'm wondering if anybody either knows a way I can catch this and throw it out (because I don't care about this error as long as it doesn't make the game crash) or can explain why it might be happening. I know Objective-C does weird things with the "nil" value, so I'm guessing it's pointing to some weird space that is neither an object pointer or nil.
EDIT: Just to clarify, I know the below code is wrong, it's what I was guessing was happening in my program. I was asking if that would cause a problem - which it indeed does. :-)
EDIT: Looks like there is a fringe case that allows you to select an Entity before it gets erased. So, it appears the progression of the code goes like this:
selectedEntity = obj;
NSAutoreleasePool *pool = ...;
[obj release];
if (selectedEntity != nil && etc...) {}
[pool release];
So I'm guessing that because the Autorelease pool has not yet been released, the object is not nil but its retain count is at 0 so it's not allowed to be accessed anyway... or something along those lines?
Also, my game is single-threaded, so this isn't a threading issue.
EDIT: I fixed the problem, in two ways. First, I didn't allow selection of the entity in that fringe case. Second, instead of just calling [entities removeObjectAtIndex:i] (the code to remove any entities that will be deleted), I changed it to:
//Deselect it if it has been selected.
if (entity == selectedEntity)
{
selectedEntity = nil;
}
[entities removeObjectAtIndex:i];
Just make sure you are assigning nil to the variable at the same time you release it, as jib suggested.
This has nothing to do with short circuiting. Objective-C eats messages to nil, so the check for selectedEntity != nil isn't necessary (since messages-to-nil will return NO for BOOL return types).
EXC_BAD_ACCESS is not a catchable exception. It is a catastrophic failure generally caused by trying to follow in invalid pointer.
More likely than not, whatever object selectedEntity points to has been released before the code is executed. Thus, it is neither nil nor a valid object.
Turn on NSZombies and try again.
If your app is threaded, are you synchronizing selectedEntity across threads properly (keeping in mind that, in general, diddling the UI from secondary threads is not supported)?
Your post was edited to indicate that the fix is:
//Deselect it if it has been selected.
if (entity == selectedEntity)
{
selectedEntity = nil;
}
[entities removeObjectAtIndex:i];
This fixes the issue because the NSMutableArray will -release objects upon removal. If the retain count falls to zero, the object is deallocated and selectedEntity would then point to a deallocated object.
if an object (selectedEntity) has been released and dealloc'd it is not == nil. It is a pointer to an arbitrary piece of memory, and deferencing it ( if(selectedEntity!=nil ) is a Programming Error (EXC_BAD_ACCESS).
Hence the common obj-c paradigm:-
[selectedEntity release];
selectedEntity = nil;
i just read this http://developer.apple.com/mac/library/qa/qa2004/qa1367.html which indicated that the error you are getting is a result of over-releasing the object. this means that altough selectedEntity is nill, you released it to many times and it just not yours to use anymore..
Put a breakpoint on OBJC_EXCEPTION_THROW and see where it is really being thrown. That line should never throw a EXC_BAD_ACCESS on its own.
Are you perhaps doing something within the IF block that could cause the exception?
selectedEntity = obj;
NSAutoreleasePool *pool = ...;
[obj release];
if (selectedEntity != nil && etc...) {}
[pool release];
You have a dangling pointer or zombie here. The selectedEntity is pointing at obj which gets releases right before you reference selectedEntity. This makes selectedEntity non-nil but an invalid object so any dereference of it will crash.
You wanted to autorelease the obj rather than release it.

iPhone - dealloc - Release vs. nil

Wondering if someone with experience could possibly explain this a bit more. I have seen examples of...
[view release];
view = nil;
....inside the (void) dealloc.
What is the difference and is one better then the other?
What is the best way?
When doing retainCount testing I have personally seen nil drop a count from 3 to 0 for me, but release only drops it from 3 to 2.
What you have seen is probably these:
1) [foo release];
2) self.bar = nil;
3) baz = nil;
Is releasing the object, accessing it through the instance variable foo. The instance variable will become a dangling pointer. This is the preferred method in dealloc.
Is assigning nil to a property bar on self, that will in practice release whatever the property is currently retaining. Do this if you have a custom setter for the property, that is supposed to cleanup more than just the instance variable backing the property.
Will overwrite the pointer baz referencing the object with nil, but not release the object. The result is a memory leak. Never do this.
If you are not using properties (where self.property = nil will also release an object) then you should ALWAYS follow a release by code that sets the reference to nil, as you outlined:
[view release]; view = nil;
The reason is that it avoids he possibility that a reference can be used that is invalid. It's rare and hard to have happen, but it can occur.
This is even more important in viewDidUnload, if you are freeing IBOutlets - that's a more realistic scenario where a reference might go bad because of memory warnings unloading a view, and then some other code in the view trying to make use of a reference before the view is reloaded.
Basically it's just good practice and it will save you a crash at some point if you make it a habit to do this.
#bbullis22 you have seen the restain count drop from 3 to 0 because you set the reference to nil. then you asked for the retaincount of 'nil' which is zero. however, the object that used to be referenced has the same retain count - 1 (due to setting the reference to nil).
using release, the reference still references the same object, so that's why you see the retain count drop from 3 to 2 in this situation.
As far as usage inside your code, in your dealloc you don't need the assignment to the property, releasing is all you need to do.
- (void)dealloc {
[myProperty release]; // don't need to assign since you won't have the object soon anyway
[super dealloc];
}
I think using both is kind of safety net. With only release in place you could run in problem if you screwed reference counting management. You would release an object, giving its memory back to system but pointer would be still valid.
With nil you are guaranteed that program will not crash since sending message to nil does nothing.