PDA

View Full Version : Getting crazy also with EXC_BAD_ACCESS




jivaro
Jun 1, 2012, 01:08 PM
I have the same problem that TheLutariFan exposed in a similar thread. The difference is that in my case I have a class instance defined and initialized whose contents is read from a file when I press a button in my interface window.

The first time that I press the button and I read the file, everything works ok: before the read operation I look at the class instance with the help of the debugger, and the instance is there with 0 objects inside (the class is a NSMutableArray of other objects). After reading from the file, the instance of the class is still there with 3 objects read from the file. Everything is fine. Then the method associated with the read button action function ends.

The next time that I press the read button, when I enter the read button action function, the class has no longer the 3 objects that where left the last time, in fact the debugger does not tell that it has any object (no 0 object message appears when looking at the class instance).

I don't know what has happened before the previous exit of the button function and the current entering, but my class instance contents has disappeared and the class does not show any longer any object inside. Afterwards, the EXC_BAD_ACCESS message appears.

I know that is quite a weird thing to explain in plain text with no code, but the facts are as I have described.

What may happen between the 2 button function calls that destroys, or deallocates my class ? What does it mean when I look at my class and no "n object" message appears ?

Is there the possibility in the debugger to place watchpoints in variables or memory locations so that when some part of the code modifies these locations or variables, the debugger stops and then we can see what part of the code has modified them ?

There are 4 days that I'm stuck here, and I don't know what to do. Any hint would be very much appreciated.

Thanks and best regards

Joan



chown33
Jun 1, 2012, 01:25 PM
Post your code.

We can't debug descriptions alone.


I don't know what has happened before the previous exit of the button function and the current entering, but my class instance contents has disappeared and the class does not show any longer any object inside. Afterwards, the EXC_BAD_ACCESS message appears.

No one else knows either, without seeing your actual code.

A likely guess is that you've under-retained or over-released an object. But frankly, that's just a guess.

You could enable Zombies and run Instruments (google it), and it would tell you about under-retains or over-releases.


... deallocates my class ...

Classes aren't dealloc'ed. Only instances are. Another reason to post your code.

jivaro
Jun 1, 2012, 01:57 PM
Post your code.
We can't debug descriptions alone.


The read class instance code:

- (IBAction) actionButtonRead:(id)sender
{
// [myAgenda deallocAgenda];
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
NSString *path = [bundlePath stringByAppendingString:@"/Agenda.xxx"];
myAgenda=[NSKeyedUnarchiver unarchiveObjectWithFile: path];
}

My class definition:

@interface Agenda: NSObject
{
NSMutableArray *book;
}

- (void) initAgenda;
- (void) addEntry: (AgendaEntry *) theEntry;
- (int) entries;
- (NSMutableArray *) getBook;
- (void) deallocAgenda;

@end

and its implementation:

@implementation Agenda;

- (void) initAgenda
{
book = [[NSMutableArray alloc] init];
}

- (void) addEntry: (AgendaEntry *) theEntry
{
[book addObject: theEntry];
}

- (int) entries
{
return [book count];
}

- (NSMutableArray *) getBook
{
return book;
}

-(void) deallocAgenda
{ int i=0;

for (AgendaEntry *entry in book)
{
i=i;
[entry deallocEntry];
i=i+1;
}
[super dealloc];
}

-(void) encodeWithCoder:(NSCoder *) encoder
{
[encoder encodeObject: book forKey: @"AgendaBook"];
}

-(id) initWithCoder:(NSCoder *) decoder
{
book = [[decoder decodeObjectForKey: @"AgendaBook"] retain];
return self;
}



As you can see, I commented out the deallocAgenda call because I was not sure if it was correct or not, but my problem has nothing to do with it. It happens with and without deallocAgenda. It happens between the exit of the first actionButtonRead IBAction and the entry of the following one: before leaving, the class instance with the 3 objects is there. When entering again, it's gone :confused:


Joan

----------


A likely guess is that you've under-retained or over-released an object. But frankly, that's just a guess.


I do nothing (or at least, I'm not aware of doing anything...) between read button clicks....


You could enable Zombies and run Instruments (google it), and it would tell you about under-retains or over-releases.


Thanks for the suggestion: I did not know the existence of instruments. I will try to use it.


Classes aren't dealloc'ed. Only instances are. Another reason to post your code.

You are right. Still getting used to classes and instances terminology (Coming from the old procedural times)

chown33
Jun 1, 2012, 02:44 PM
myAgenda=[NSKeyedUnarchiver unarchiveObjectWithFile: path];


Who owns the object returned from unarchiveObjectWithFile: ? If you don't know what it means to own an object, you need to read the Advanced Memory Management Guide (https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html).

You should also post what resource (book, tutorial, whatever) you're learning from, because it should have explained object ownership (or release/retain).

If you haven't gone through a book or tutorial, you should. You're missing a lot of fundamentals here (like retain/release), and the code that does pertain to memory management (dealloc) is totally wrong.


-(void) deallocAgenda
{ int i=0;

for (AgendaEntry *entry in book)
{
i=i;
[entry deallocEntry];
i=i+1;
}
[super dealloc];
}

This code is wrong on several levels.

First, you never have to dealloc any object that resides within a container you own. If you owned book, then simply releasing it (not deallocing it or its contents) is all you should do. And if you don't own book, then dealloc'ing or releasing it is even more wrong.

Second, you should never dealloc any object other than self. Never. If you think you should, then you're using memory management (retain/release) wrong.

Third, you named the method deallocAgenda, rather than dealloc. This means it won't be called at the right time. In fact, it won't be called at all.

In general, all the memory management in the class is wrong. You're not retaining things that should be owned. You're not releasing them, you're dealloc'ing. You're dealloc'ing members of a collection when it's unnecessary. You didn't put [super dealloc] in the right method. It's about as completely wrong as it could possibly get.

You really need to read and understand how memory management works. And you need to follow the memory management rules.

jivaro
Jun 1, 2012, 04:50 PM
Who owns the object returned from unarchiveObjectWithFile: ? If you don't know what it means to own an object, you need to read the Advanced Memory Management Guide (https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html).

You should also post what resource (book, tutorial, whatever) you're learning from, because it should have explained object ownership (or release/retain).

If you haven't gone through a book or tutorial, you should. You're missing a lot of fundamentals here (like retain/release), and the code that does pertain to memory management (dealloc) is totally wrong.


I'm studying "Programming in Objective C" - Stephen G. Kochan. I'm very sorry to say that one of the chapters that I have read several times but I still do not grasp is Chapter 17 ("Memory Management"). Following your comments I will insist and retain my programming desires till I get a better understanding of it.

I have bought also "Cocoa Programming - Developer's Handbook" - David Chisnal, but I still have not started it seriously. I want to learn before Objective C.


This code is wrong on several levels.

First, you never have to dealloc any object that resides within a container you own. If you owned book, then simply releasing it (not deallocing it or its contents) is all you should do. And if you don't own book, then dealloc'ing or releasing it is even more wrong.


The code is probably wrong, but it was intended to release the contents before deallocating the container:

-(void) deallocAgenda
{ for (AgendaEntry *entry in book)
{
[entry deallocEntry];
}
[super dealloc];
}
....
-(void) deallocEntry
{
[startDate release];
[entryText release];
}




Second, you should never dealloc any object other than self. Never. If you think you should, then you're using memory management (retain/release) wrong.

Third, you named the method deallocAgenda, rather than dealloc. This means it won't be called at the right time. In fact, it won't be called at all.


deallocAgenda was called in the commented line. I commented the line to try to keep things as simple as possible and isolate the origin of my problem. Better a memory leak than a program crash.


- (IBAction) actionButtonRead:(id)sender
{
// [myAgenda deallocAgenda];
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
NSString *path = [bundlePath stringByAppendingString:@"/Agenda.xxx"];
myAgenda=[NSKeyedUnarchiver unarchiveObjectWithFile: path];
}




In general, all the memory management in the class is wrong. You're not retaining things that should be owned. You're not releasing them, you're dealloc'ing. You're dealloc'ing members of a collection when it's unnecessary. You didn't put [super dealloc] in the right method. It's about as completely wrong as it could possibly get.


In this case, the only thing I can say is sorry for asking things that I should know. I will reread the memory management chapter and the links you have included in your reply.



You really need to read and understand how memory management works. And you need to follow the memory management rules.

Following your comments I'm afraid that you are completely right. Thanks for your suggestions and your patience.

Joan

Sydde
Jun 1, 2012, 08:49 PM
It looks to me like you need to understand what it means to override a method and when you should or should not. "super" is typically only invoked from a method that has exactly the same name, though there are probably exceptions.