EXC_BAD_ACCESS error

Discussion in 'Mac Programming' started by BadWolf13, Mar 12, 2010.

  1. BadWolf13 macrumors 6502

    Joined:
    Dec 17, 2009
    #1
    Ok, so here's an interesting problem with a Cocoa application I'm building.

    The basis of this application is an NSMutableArray. When I close the program, it uses this code to save the array;

    Code:
    	NSString *path = [self pathForDataFile]; 
    	
    	NSMutableDictionary *rootObject; 
    	rootObject = [NSMutableDictionary dictionary]; 
    	
    	[rootObject setValue: partsList forKey:@"partsList"]; 
    	[NSKeyedArchiver archiveRootObject: rootObject toFile: path];
    Then, when the program starts, it uses the following code to load the array(after initializing it of course);

    Code:
    	NSString *path = [self pathForDataFile]; 
    	NSDictionary *rootObject; 
    	
    	rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 
    	setPartsList: [rootObject valueForKey:@"partsList"]; 
    
    Now, when I run the program once, it works fine. When I close it, it creates the data file. However, when I run the program a second time to load the saved information, I get a EXC_BAD_ACCESS error sometime after it loads the array. Could this have something to do with access permissions for the file in question?

    PS. I looked up this error message, and everything I find on google points to memory management issues dealing with retaining and releasing objects. My understanding is that since my project is set to use Garbage Collector, I don't have to worry about retain, release and autorelease commands, is that correct?
     
  2. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    When you get that error, is the debugger available? If so, what's the stack trace look like?

    Is the last line of the code you posted correct? I would guess that doesn't compile.
     
  3. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #3
    I'm not sure what you mean by stack trace. The debugger is available though.

    I've actually changed my code. It doesn't give me the error anymore, but it either doesn't save the array, or doesn't load the array. I'm not sure which.

    The saving code is now;

    Code:
    	NSString *path = [self pathForDataFile]; 
    	[NSKeyedArchiver archiveRootObject: partsList toFile: path];
    
    While the loading code is now;

    Code:
    	NSString *path = [self pathForDataFile]; 
    	setPartsList:[NSKeyedUnarchiver unarchiveObjectWithFile:path];
    
    I didn't see any reason to use the NSMutableDictionary, so I replaced it with the setter and getters for the partsList array, which is the array that I want to save. Like I said, I'm not getting the error anymore, but when I close and re-open the application, it's starting with a blank array instead of the saved version.
     
  4. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #4
    heh, ok I understand the problem now.

    Code:
    setPartsList:[NSKeyedUnarchiver unarchiveObjectWithFile:path];
    This isn't doing what you think it's doing. Let me rewrite it:

    Code:
    setPartsList:
        [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    Instead of assigning partsList to the unarchived object, you're defining a label for use with the C goto statement, and then ignoring the result of unarchiveObjectWithFile.

    Try this instead:

    Code:
    partsList = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    Or if you have setPartsList: defined as a method you can use that too:

    Code:
    [self setPartsList:[NSKeyedUnarchiver unarchiveObjectWithFile:path]];
     
  5. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #5
    Thanks dude, I used your second example and it works perfectly now.

    Question though. In some applications, I've been able to call a method within the same class without calling it as [self method]. Is there some rule as to when I need to call "self" and when I don't?
     
  6. Daphtdazz macrumors member

    Joined:
    Nov 10, 2007
    Location:
    Oxford
    #6
    Hey,

    Objective-C is essentially just an extension to C (with a modified run-time and all that behind the scene). Thus, if you write a bit of code that would mean a certain thing in C, that is what it will mean in Objective-C.

    So if you write what you wrote above, that would be defining a label for the goto command, as said.

    The only way that you can send an objective-C message is by using the

    [target method]

    syntax.

    So if you have an instance variable and you want to access it within your class's implementation, you could access it directly, or by calling its getter method, which will often have the same name as the variable. Thus you have two things which look the same, and get the same result, but are completely different in implementation.

    So, if I have a class:

    @interface AClass : NSObject {
    id someObject;​
    }

    -(void)aMethod;
    -(id)someObject;

    @end

    @implementation AClass
    -(void)aMethod{
    [someOtherObject doSomethingWith:someObject];​
    // Or:
    [someOtherObject doSomethingWith:[self someObject]];​
    }
    -(id)someObject{
    return someObject;​
    }
    @end

    In the first version, someObject is the actual object, and in the second someObject is a selector that you pass to AClass to get the instance variable.

    Hope this helps.
     
  7. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #7
    Do C programmers ever actually use goto? Last time I used anything like that was with Commodore BASIC. It almost seems like bad form, I personally would not object to having labels and goto simply go to the dustbin of history.
     
  8. Cinder6 macrumors 6502

    Cinder6

    Joined:
    Jul 9, 2009
    #8
    Not usually, no, but it's there. I've seen a couple examples where goto is more elegant than other methods, but they were just proof-of-concepts.
     
  9. jpyc7 macrumors 6502

    Joined:
    Mar 8, 2009
    Location:
    Denver, CO
    #9
    I see goto in network driver code to deal with errors. This is because nearly all drivers are written in C (not C++ where there is support for exceptions) which is because a lot of unix-like OSes (FreeBSD, Linux) are written in C.

    I'm weak on Obj-C, but I think it has to do with whether it is a class method or not. That is the terminology used in C++ when a method belongs to the class and not a single instance. You don't need the self for class methods.
     
  10. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #10
    Thanks Daphtdazz, that does help explain it.

    My last question on this topic. In the future, I'm going to rewrite the save and load methods to save and load three separate arrays. As I'll be using NSKeyedArchiver and NSKeyedUnarchiver, does it matter what order I put the archiving and unarchiving commands, or will they always find the right data because they're keyed?
     
  11. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #11
    It doesn't matter, but you probably want to error-check for the existence of each key first, and have a default value ready in case it doesn't exist, or throw an exception/alert.
     
  12. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #12
    Apple uses it a lot, just look through some of their kernel code. It's nice when using lots of Core Foundation objects to give your function a clean structure and separate all the release/frees from the actual logic.
     
  13. Daphtdazz macrumors member

    Joined:
    Nov 10, 2007
    Location:
    Oxford
    #13
    I suppose it's like a lot of things in coding. If used responsibly and with a particular design and methodology in mind, goto commands are very powerful and can greatly clarify code.

    However, new programmers are told that they must never use them, which generally will be good advice because you don't achieve great code design and methodology over night... the potential for bollocksing it all up is large.
     
  14. Krevnik macrumors 68040

    Krevnik

    Joined:
    Sep 8, 2003
    #14
    That's usually where I see it a lot as well. It helps when someone comes after you trying to maintain the code, as they can see where cleanup is done, and don't have to have quite as intimate a knowledge of the function in order to modify it to do something new or fix a bug.
     
  15. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #15
    Is the code that you posted exactly what you are running? In that case, turn on all the compiler warnings. And figure out why you get a warning for an "unused label". And probably a warning that setPartsList is used without being defined.

    You always send a method to some object. Object methods are often sent to self, or to some other object. Class methods are sent to a class. But there is always _some_ receiver for the message.
     
  16. Jimmetry macrumors member

    Joined:
    Feb 11, 2009
    #16
    I know this is an oldish thread but EXC_BAD_ACCESS is almost always caused by bad memory management. I happened to find this thread by naively running into the same issue.

    If you don't alloc it, you can't keep it unless you retain it.

    partsList = [[NSKeyedUnarchiver unarchiveObjectWithFile: path] retain];

    Otherwise it'll be alive until the function returns but no guarantees past that point.
     
  17. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #17
    Even then, if you are using an autorelease pool (e.g., threading) that should be drained periodically within a long loop, you need to make sure not to lose things (like enumerators or scanners) when you between pools.
     
  18. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #18
    Just to double check something. My understanding from Aaron Hillegass' book is that if you're using Garbage Collector, you don't need to bother with retain, release or autorelease. Is that right?
     
  19. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #19
    yes, that's right. You can still do them to your hearts content, but they won't have any affect.

    -Lee
     
  20. Jimmetry macrumors member

    Joined:
    Feb 11, 2009
    #20
    Was the "PS" part of your original post always there? Somehow I missed it. Well yes, the garbage collector will indeed handle all that for you.

    In that case, you should be checking to make sure the object was created. A bit of error handling will stop EXC_BAD_ACCESS (and instead you can show a dialog), and if NSKeyedUnarchiver gives detailed exception reasons, it might also tell you why the problem is occurring in the first place.
     
  21. Jimmetry macrumors member

    Joined:
    Feb 11, 2009
    #21
    There are a few circumstances where it can be useful (which is probably why it still exists) but it's not popular. The only accepted goto-esque feature is the switch statement.
     

Share This Page