EXC_BAD_ACCESS on iPhone when using "obj != nil - iphone

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.

Related

Can we check if the object is nil or not, before going to release in dealloc method of a class

Can we check the object is nil or not before going to release in dealloc method. I am new to objective C. Is this right way to avoid segmentation issues?.
-(void)dealloc{
if(stringObject!=nil){
[stringObject release];
}
}
Testing for nil before release is fully redundant in Objective C and will not add any resiliency to your code.
Indeed, the whole point of segmentation faults (EXC_BAD_ACCESS) is having a pointer which is not nil, thus points to some memory, and accessing that piece of memory after it has been freed.
If the pointer is nil in the first place you will not be possibly able to access any memory with it and you will not have a segmentation fault in Objective C (unlike C or C++).
The real solution to segmentation faults is correct memory management. If retain/release management seems too complex, you can have a look at ARC, which has its own intricacies, though (although much less than manual retain/release management).
A simple
if(stringObject)
will do, if you just want to check if the variable points to an object.
But with Objective C it is not necessary to test for nil because an message to a null object will simply do nothing. So it is enough to say:
-(void)dealloc
{
[stringObject release];
stringObject = nil;
[super dealloc]; //added because of the comments
}
Under ARC, you can leave out the whole dealloc in most situations, because 1) the release is managed automatically, and 2) the call to dealloc is the made just before the object ends it's life, so the nil is not necessary. However, if you use custom c-style allocation you may still need an alloc method. But this belongs to an advanced topic.
Here's a link to the dev guide on working with objects in general:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW1
This suffices as a nil test (your way is also correct, just slightly longer):
if (stringObject)
{
//do something
}
But in a simple case like yours, you don't even have to do that, because in Objective-C, sending messages to nil objects just means nothing happens:
[aNilObject doSomething]; //nothing happens, this is perfectly valid and won't throw an exception; it won't even log anything. Once you're used to it, it's great and avoids lots of boilerplate nil checks.
Going further, in your case, you should switch to ARC (after you're done learning manual retain and release, which is a good exercise).
Your code would then look like this:
//you don't need to call dealloc at all in ARC :)
Yes you can. Before ARC there was a very common macro defined
#define SAFE_RELEASE(object) if (object != nil) { [object release]; object = nil; }
NOTE: However, sending a message to nil will return nil.

problem with nil and release?

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; .

Printing an NSMutableArray causes crash with no error code

I determined that my application crashes on the following line:
if(sourceValues != nil && [sourceValues class] == [NSMutableArray class])
[sourceValues release];
"sourceValues" is declared as an NSMutableArray at the top of my class. The "if" loop is satisfied, and the [sourceValues release] call gets made, which crashes the program with no error code. So, since sourceValues != nil and since [sourceValues class] == [NSMutableArray class], I wanted to see exactly what sourceValues was. So, above the "if" loop I added the following:
NSLog(#"sourceValues is %#", sourceValues);
But my program will not print it. It just crashes with no error code on that line. So, if sourceValue exists and if it an NSMutableArray, why will it not be printed. What is the problem here?
I'm trying to have code that says "if sourceValues has been allocated, release it." How can I do this?
Why not use:
if(sourceValues != nil && [sourceValues isKindOfClass:[NSMutableArray class]])
[sourceValues release];
You may want to use other methods like:
isMemberOfClass:
If this...
NSLog(#"sourceValues is %#", sourceValues);
... is crashing your program, it is because sourceValues has already been released. Wherever you release sourceValues, set it to nil.
[sourceValues release], sourceValues = nil;
If your app is still crashing, it is because the array has been over-released somewhere else. That is, you didn't correctly balance retains and releases. First, try "build and analyze" and fix any problems the static analyzer identifies. Next, turn on zombie detection and see where you are first messaging the over-released object.
Note that [sourceValues class] == [NSMutableArray class] will not work and that pattern should never be used to check if an instance is of a particular class. You should always use isKindOfClass: or isMemberOfClass:.
However, since you can't tell the difference between a mutable or immutable array anyway, there is no point to checking in the first place.
Well, first off, there's no danger in releasing a nil object. So the issue of "if sourceValues has been allocated, release it." is probably superfluous. Unless you're doing some funky stuff, you should follow regular memory management rules and just call [sourceValues release]; in dealloc
Have you tried running everything with breakpoints on ("Build and Debug - Breakpoints On" in Xcode)? That usually gives you more debug information than the usual "Build and run".
It might be (I'm guessing based on some odd problems I've had in the past) that you've actually dealloced sourceValues already but the pointer is still pointing to its old memory. If that happens, a new object might be situated in that area which the program will attempt to treat like an NSMutableArray anyway.
Try checking the retainCount, something like:
NSLog(#"retain count: %d", [sourceValues retainCount]);
ONLY use for testing/debugging, don't rely on this in an if statement.
Also, you can try iterating over sourceValues and print its contents to NSLog, but I have no idea what's in there.
BEST thing to do is setup a class property as an MSMutableArray with RETAIN, and use synthesize. The dealloc will take care of the release.
If the above is implemented, you can alloc/init as follows:
self.sourceValues = [[[NSMutableArray alloc] init] autorelease];
and then add objects directly to self.sourceValues as needed. No need to worry about releasing, it will be done in dealloc.

iphone - testing if an object exists

I have several objects in my app that can become nil at some point and I have methods that in theory are used to put these objects to nil.
But, if I try to put to nil an object that does not exist, the app will crash.
for example...
[object1 release];
object1 = nil;
//... and after that
[object1 removeFromSuperview]; // this will crash
Then I thought, why not testing to see if the object exists before removing...
if (object1 != nil)
[object1 removeFromSuperview];
// this will crash too, because object1 cannot be tested for nil because it does not exist
How can I check if the object exists before testing if it is nil?
something as
if (object1 exists( {
if(object1 != nil))
[object1 removeFromSuperview)
}
is this possible?
I ADDED THIS TO CLARIFY...
what I mean is this: imagine I have object1 declared on the header and initialized on the code. So, it exists and points to a valid reference. At some point, the object may be released, so the reference still points to an object but the object was freed. Even if I put the object to nil after releasing, I cannot do anything with it.
The problem is this: I have some methods that are asynchronous. One of them scans for some objects and remove them if they are found. I must check if the object exists and the reference points to a valid object before releasing it again. This is the point: how do I test if the object exists and its reference points to a valid existent object before releasing it again, to void releasing again an object that is already released and crash the app.
In short, your question of determining if the pointer is still valid is going down the wrong path.
After you release an object, you must immediately set its value to null so that you no longer control it. If two methods are running asynchronously accessing the same object, they must be synchronized at that point so that releasing and setting to null happens at the same time in one thread before the other has a chance to interrupt.
Are you just speculating, or have you actually tried this? Because in other programming languages, invoking a method on nil will cause a crash. In Objective-C this is not true. In Objective-C, you CAN send messages to nil without causing a crash. These messages simply have no effect.
In fact, you can be really obscene and do the following without a crash:
[(id)nil setTitle:#"Testing"]; // This will not cause a crash
If your app is crashing, it is not because you are messaging nil. It is possible, however, that you are failing to set a pointer to nil and you are messaging an object in memory that you do not own. Given the details you provided in your update, namely that you have an asynchronous thread accessing these objects, I think it is very likely you are sending messages to pointers whose object has already been released, but have not yet been set to nil.
I have compared an object to nil before without any problems.

Why should a self-implemented getter retain and autorelease the returned object?

Example:
- (NSString*) title {
return [[title retain] autorelease];
}
The setter actually retained it already, right? and actually nobody should bypass the Setter... so I wonder why the getter not just returns the object? It's actually retained already. Or would this just be needed in case that in the mean time another objects gets passed to the setter?
From here http://www.macosxguru.net/article.php?story=20030713184140267
- (id)getMyInstance
{
return myInstanceVar ;
}
or
- (id)getMyInstance
{
return [[myInstanceVar retain] autorelease] ;
}
What's the difference ?
The second one allows the caller to get an instance variable of a container object, dispose of the container and continue to play with the instance variable until the next release of the current autoreleased pool, without being hurt by the release of the instance variable indirectly generated by the release of its container:
aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);
If the "get" is implemented in the first form, you should write:
aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];
The first form is a little bit more efficent in term of code execution speed.
However, if you are writing frameworks to be used by others, maybe the second version should be recommanded: it makes life a little bit easier to people using your framework: they don't have to think too much about what they are doing…;)
If you choose the first style version, state it clearly in your documentation… Whatever way you will be choosing, remember that changing from version 1 to version 2 is save for client code, when going back from version 2 to version 1 will break existing client code…
It's not just for cases where someone releases the container, since in that case it's more obvious that they should retain the object themselves. Consider this code:
NSString* newValue = #"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue
This looks reasonable, but if neither the setter nor the getter uses autorelease the "Go on to do something" part will likely crash, because oldValue has now been deallocated (assuming nobody else had retained it). You usually want to use Technique 1 or Technique 2 from Apple's accessor method examples so code like the above will work as most people will expect.
Compare this code
return [[title retain] release]; // releases immediately
with this
return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
The second one guarantees that a client will have a non-dealloced object to work with.
This can be useful in a situation like this (client code):
NSString *thing = [obj title];
[obj setTitle:nil]; // here you could hit retainCount 0!
NSLog(#"Length %d", [thing length]); // here thing might be dealloced already!
The retain (and use of autorelease instead of release) in your title method prevents this code from blowing up. The autoreleased object will not have its release method called until AFTER the current call stack is done executing (end of the current run loop). This gives all client code in the call stack a chance to use this object without worrying about it getting dealloc'ed.
The Important Thing To Remember: This ain't Java, Ruby or PHP. Just because you have a reference to an object in yer [sic] variable does NOT ensure that you won't get it dealloc'ed from under you. You have to retain it, but then you'd have to remember to release it. Autorelease lets you avoid this. You should always use autorelease unless you're dealing with properties or loops with many iterations (and probably not even then unless a problem occurs).
I haven't seen this pattern before, but it seems fairly pointless to me. I guess the intent is to keep the returned value safe if the client code calls "release" on the parent object. It doesn't really hurt anything, but I doubt that situation comes up all that often in well-designed libraries.
Ah, ok. from the documentation smorgan linked to, it seems this is now one of the methods that Apple is currently recommending that people use. I think I still prefer the old-school version:
- (NSString *) value
{
return myValue;
}
- (void) setValue: (NSString *) newValue
{
if (newValue != myValue)
{
[myValue autorelease]; // actually, I nearly always use 'release' here
myValue = [newValue retain];
}
}