I have an array of 5 items that is also used as the content for a tableview. In the nib is a button that changes the content of the array to 5 different items. When I click that button, however, the app crashes with an EXC_BAD_ACCESS. I set a breakpoint on objc_exception _throw and had my suspicions confirmed. The bad method is
- (id)tableView:(NSTableView *)wordsTableView
objectValueForTableColumn:(NSTableColumn *)column
row:(int)rowIndex
{
return [[currentCard words] objectAtIndex:rowIndex];
}
currentCard is an instance of the GameCard class, and its array, words, is the array in question. On first launch, it works fine, but if I try to change it, crash.
----------EDIT----------
In AppController's awakeFromNib: I have this
currentCard = [[GameCard alloc] init];
And in the button's IBAction, I have this:
[currentCard release];
currentCard = [[GameCard alloc] init];
With zombies enabled, when I click the button, I get this from GDB:
2009-06-22 18:55:03.368 25WordsMax[19761:813] *** -[CFArray objectAtIndex:]: message sent to deallocated instance 0x14ba00
referring to the data source method. I've been trying to track down the memory bug for hours, but am missing it.
I got so frustrated I commented out every retain & release (no autoreleases) in the code and still get 2009-06-22 19:41:58.564 25WordsMax[21765:813] *** -[CFArray objectAtIndex:]: message sent to deallocated instance 0x14c330 when I hit the button.
And what is calling the datasource method? I'm not calling reloadData. If in my datasource method, I return #"A Word" for each row, everything runs fine. In GDB, I can even see my NSLogs printing the contents of the new array, all without a hitch. It's only when the datasource method as seen in the question gets called that any problems happen.
2009-06-22 18:55:03.368 25WordsMax[19761:813] *** -[CFArray objectAtIndex:]: message sent to deallocated instance 0x14ba00
Read that carefully. The receiver was an instance of CFArray, and the message selector was objectAtIndex:.
The deallocated instance was an array, not a game card.
Your game card owns the array, so it must retain it in some way. This means you must either:
Create the array using alloc and init (and not autorelease it).
Retain it.
Make its own copy. (Preferable if you're receiving an array from another object, as in your setter, since the array you receive may be mutable, and you don't want the other object mutating “your” array.)
If you synthesize your accessors, declare the property as either #property(retain) or #property(copy). Note that this won't work if you want a mutable copy; in that case, you'll have to implement the setter yourself.
Sounds like you have a reference counting error somewhere, which isn't going to be debuggable from just that snippet of code. Try running with NSZombieEnabled=1, and then looking for retain/release bugs where you manage whatever object you get zombie warnings about.
NSZombie is telling you that the object returned from [currentCard words] is getting released somewhere, then you're using it again. Check all of your assignments to that variable and make sure that you're not setting it to an autoreleased object. Then check all release and autorelease messages sent to it.
It may help to see the GameCard Init and the GameCard dealloc method.
Also to verify that the method you think is the problem is the problem I would check for nil
if( [currentCard words] != nil )
return [[currentCard words] objectAtIndex:rowIndex];
else
return #"Blah!";
Related
I ran into this problem while trying to fix a memory leak with the facebook-ios-sdk. How do i handle this situation when passing objects from no arc compiled classe to arc enabled classe?
This is the code inside the non arc compiled Facebook library: (i removed the unnecessary stuff which is not related to the problem) as you can see, result object is not autoreleased or released.
- (void)handleResponseData:(NSData *)data {
NSError* error = nil;
id result = [self parseJsonResponse:data error:&error];
self.error = error;
// Call the defined delegate wich is my AppDelegate didLoad method wich is arc enabled
[_delegate request:self didLoad:result];
}
- (id)parseJsonResponse:(NSData *)data error:(NSError **)error {
SBJSON *jsonParser = [[SBJSON alloc] init];
//gets the object wich leaks or gets overreleased
id result = [jsonParser objectWithString:responseString];
[jsonParser release];
return result;
}
Now if i try to add autorelease to the result object, i am facing a NSZombie when my arc code in my AppDelegate try's to release the object. However if i leave the code like this i'm facing memory leaks whit the result object which gets not released.
am i missing something basic? i can't get my head around this?
Thanx for any advice! Chris
The result returned from -parseJsonResponse:... is autoreleased already (see note at bottom).
Since the name of the -parseJson method doesn't begin with new, alloc, copy or mutableCopy, the compiler assumes that it returns an object with a +0 reference count, meaning it needs to be retained by the calling code if it is to be kept around, and doesn't need to be released if it's not being kept around. That's a long winded way of saying that it should neither leak nor cause a crash in your ARC code as written in your question.
Passing objects between ARC code and manual reference counting code doesn't require any special handling. You just need to make sure that methods' names match their memory management semantics in the non-ARC code. It certainly seems like you've done that in this case, although as you say, you didn't post your complete code.
Note: Presumably, objectWithString: returns an autoreleased object. If it doesn't it, it should (because it doesn't start with alloc, new, copy, mutableCopy).
I work on implementation of playing card class and i've created the following method:
+ (id)cardWithCard:(Card *)newCard
{
Card *card = [[[Card alloc] initWithCard:newCard] autorelease];
return card;
}
i use autorelease method here cause otherwise Product->Analyze warns me about potential leak. Everything works fine until variable myCard (which was allocated earlier) to which a new value was assigned like this:myCard = [Card cardWithCard:newCard] is sent to a different method as a parameter. It turns out to be deallocated there and my app crashes.
How should i resolve this issue? Get autorelease method away despite warnings of Analyze?
Each method or object should be responsible for retaining object that it is interested in.
It it easier to maintain. (Exception are for method that have alloc, new or copy in there name, they will return an object that the caller is responsible to release.)
So you need to keep the autorelease because that method don't exist after the return and won't be able to call release on it.
The Object that is calling cardWithCard should retain the object if it want it to be alive more that the time of that particular method.
The code should look something like this
self.myCard = [Card cardWithCard:newCard];
This is in the case where myCard is declare like this
#property (nonatomic, retain) Card * myCard;
So in this case the property will do the retain for you and will release that object when you will place a new one in this property. (If you overwrite the auto-generated accessor, you will need to manage that yourself in those method)
If for some reason you don't want to use a property... well it's your choice :-)
You will need to do something like this:
myCard = [[Card cardWithCard:newCard] retain];
and you will need to something like this later on
[myCard release];
If it's not in the same method the analyser will compline, and if it's in the same method you probably don't need the retain.
I have a weird issue that comes up while releasing an object. In the object's dealloc method I am releasing another (sub) object. When this sub object is released I get an EXC_BAD_ACCESS error. I am pretty sure the sub-object is a valid pointer right before I call release on it.
This is how I've confirmed the weirdness - I set a break point inside the dealloc method, right before the release of the sub-object, and it is allocated! I can send it messages and it responds correctly. Another weird bug is that, if NSZombieEnabled is set to YES, I dont get an error at all, not even NSZombie's usual error that says I've sent a message to a deallocated object, the code runs properly.
Does anybody have any idea how to solve this?
Thanks in advance!
* EDIT 1 *
I've found out that if I place the [super dealloc] in the end of the dealloc, it crashes, but if I place it at start, it won't. I've had something similar before, only the other way - app crashed if I [super dealloc] in start of my dealloc, and didn't at the end.
Why does it make a difference and when should you use what?
* EDIT 2 *
Scratch Edit #1! It doesn't work either way.
Do your dealloc routine happen to look like this:
- (void)dealloc
{
[super dealloc];
[otherObject release];
}
if so, change the order. If you call [super dealloc], your object gets vanished from memory, trying to acces otherObject later will cause you to access non-allocated memory -> EXC_BAD_ACCESS.
Without seeing how the object is initialized, will be hard for anyone to know for sure.
MyObject *someObject = [MyObject alloc] init...]; // Make sure you aren't autoreleasing here
// do some stuff with someObject
[someObject release];
I have an NSString that I've retained, and the only place I release it is in the dealloc method. For some reason, however, later in the program when I try to reference it (its length, specifically), I get a crash, saying [CFString length]:message sent to deallocated instance 0xff32c50.
I explicitly retain the string earlier in the program. Is there any reason why this would be happening? Any help is appreciated.
The string, entityParameter, is declared in the header, and defined later.
Here is some of the code:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
The place where I'm getting the crash looks like this:
if([entityParameter length] != 0 && entityParameter != nil)
{
return;
}
I have an NSString that I've retained,
and the only place I release it is in
the dealloc method. For some reason,
however, later in the program when I
try to reference it (its length,
specifically), I get a crash, saying
[CFString length]:message sent to
deallocated instance 0xff32c50.
Obviously, it isn't retained, then.
If by "retained" you mean "assigned to a property", are you doing:
self.prop = [NSString ...];
Or:
prop = [NSString ...];
Because the former will retain (if the property is declared as retain) whereas the latter will not. Note that NSString properties should generally be declared copy, but that is orthogonal to the question).
If your code is as written:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
And you really do only release it in dealloc, then make sure your containing object hasn't already been deallocated. That may be happening. Or it might be that you've leaked the string reference somewhere and spuriously deleted it without a retain.
Using Zombie detection in instruments with "track retain/release events" (or whatever it is called) should show you every last retain/release event on the object, including the one the blew up.
I've learned that in dealloc you do [object release]; but in viewDidUnload (in a UIViewController subclass) you do self.object = nil. What is really the difference because self.object = nil (we're assuming object is a (nonatomic, retain) property) retains nil (which does nothing) and then releases the old value and then the reference count is 0 right?
self.object = nil calls your setter, which will release the old value, set the member to nil, and possibly do other things (it's a method, so it could do anything). The "anything" part of that is potentially dangerous; see this question, for example.
[object release] releases the old value, but leaves the member as a now-dangling pointer, which is a good recipe for bugs. In dealloc it doesn't really matter, since the pointer itself is about to go away too, but in any other case it's a very bad idea to release a member without setting it to nil.
(As a sidenote, you should never assume that releasing an object gives it a reference count of 0. It releases your reference, but other objects may still have references to it.)
If you do object = nil without [object release], that might causes memory leaking. If you do [object release] without object = nil afterwards, object becomes dangling pointer as #Jim suggested. self.object = nil is a sugar for setter function call.
If you just release an object, then it will become freed object.
And if you try to perform any sort of operation on freed object then your app crashes. To avoid such accidents, it is always preferred "assign your object to nil after releasing it". Because we all know any operations performed on nil will not be executed :)
If you do [object release], and want to access the object the app simply crash.
If you do object = nil, and want to access the object nothing will perform.
The reason is in the [object release], you are attempted to free the object. so its dont have any pointer (no memoty).In the object = nil, you are attempted to assign the object with null pointer. so if u trying to access the object nothing will happen.
Generally we wrote the code as [object release]; object = nil; because if u access the object unexpectedly, the app wont crashed.