Getting crazy also with EXC_BAD_ACCESS

Discussion in 'Mac Programming' started by jivaro, Jun 1, 2012.

  1. macrumors newbie

    Joined:
    Apr 21, 2012
    Location:
    Cornella de Llobregat (Spain)
    #1
    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
     
  2. macrumors 603

    Joined:
    Aug 9, 2009
    #2
    Post your code.

    We can't debug descriptions alone.


    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.


    Classes aren't dealloc'ed. Only instances are. Another reason to post your code.
     
  3. jivaro, Jun 1, 2012
    Last edited by a moderator: Jun 1, 2012

    thread starter macrumors newbie

    Joined:
    Apr 21, 2012
    Location:
    Cornella de Llobregat (Spain)
    #3
    The read class instance code:

    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:

    Code:
    @interface Agenda: NSObject
    {
    		NSMutableArray *book;
    }
    	
    - (void) initAgenda;
    - (void) addEntry: (AgendaEntry *) theEntry;
    - (int) entries;
    - (NSMutableArray *) getBook;
    - (void) deallocAgenda;
    
    @end
    and its implementation:

    Code:
    @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

    ----------

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

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

    You are right. Still getting used to classes and instances terminology (Coming from the old procedural times)
     
  4. chown33, Jun 1, 2012
    Last edited: Jun 1, 2012

    macrumors 603

    Joined:
    Aug 9, 2009
    #4
    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.

    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.


    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.
     
  5. thread starter macrumors newbie

    Joined:
    Apr 21, 2012
    Location:
    Cornella de Llobregat (Spain)
    #5
    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.

    The code is probably wrong, but it was intended to release the contents before deallocating the container:
    Code:
    -(void) deallocAgenda
    {    for (AgendaEntry *entry in book)
    	{  
     	   [entry deallocEntry];
    	}
    	[super dealloc];
    }
    ....
    -(void) deallocEntry
    {
    	[startDate release];
    	[entryText release];
    }
    

    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.

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

    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.

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

    Joan
     
  6. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #6
    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.
     

Share This Page