EXC_BAD_ACCESS from concat string w int?

Discussion in 'Mac Programming' started by Danneman101, Jan 13, 2011.

  1. Danneman101 macrumors 6502

    Joined:
    Aug 14, 2008
    #1
    I'm receiving a EXC_BAD_ACCESS-error from trying to manipulate a string, and I'm not sure exactly where it goes wrong.

    The string is a property assigned as follows:

    .h-file
    Code:
    #import <Cocoa/Cocoa.h>
    @interface TableViewController : NSTableView <NSTableViewDelegate> {
    	// other stuff...
    	NSString *str_CurrentPlist;  // <-- THE STRING	
    }
    // other stuff...
    @property (assign) NSString *str_CurrentPlist;  // <-- THE STRING
    @end
    
    .m-file
    Code:
    #import "TableViewController.h"
    @implementation TableViewController
    @synthesize str_CurrentPlist;  // <-- THE STRING
    // other stuff...
    @end
    
    I'm using it to update the plist currently loaded into the Array Controller which is bound to and thus populates a TableView.

    In my .m-file I have a function UpdateCurrentPlistString that updates that string and adds a number to it.

    Starting-value is "MENU" (which will read "MENU.plist" when in a later function I use its value to load the plist), and pressing row 1 in my tableview will give the string "MENU_1", and so on.

    Code:
    - (void)UpdateCurrentPlistString:(NSInteger *)n_row
    {
    		// IF:	"MENU"
    		// -------------------
    		if ([self.str_CurrentPlist isEqualToString:@"MENU"])
    		{
    			// SET:		Current Plist to "MENU_X"
    			self.str_CurrentPlist = [self.str_CurrentPlist stringByAppendingString:@"_"];
    			NSString *temp = [NSString stringWithFormat:@"%d", n_row];
    			self.str_CurrentPlist = [self.str_CurrentPlist stringByAppendingString:temp];			
    		}
    		
    		// ELSE :	"MENU_X"
    		// ----------------------
    		else
    		{	
    			// SET:		Current Plist to "MENU_X_Y"
    			self.str_CurrentPlist = [self.str_CurrentPlist stringByAppendingString:@"_"];
    			NSString *temp = [NSString stringWithFormat:@"%d", n_row];
    			self.str_CurrentPlist = [self.str_CurrentPlist stringByAppendingString:temp];			
    		}
    }
    
    This works fine the first time around, but the second time the function is called I receive the EXC_BAD_ACCESS-error.

    Strangely enough, altering the code a little for debugging-purposes, this does NOT give any errors:

    Code:
    - (void)UpdateCurrentPlistString:(NSInteger *)n_row
    {
    		// IF:	"MENU"
    		// -------------------
    		if ([self.str_CurrentPlist isEqualToString:@"MENU"])
    		{
    			self.str_CurrentPlist = @"MENU_1";			
    		}
    		
    		// ELSE :	"MENU_X"
    		// ----------------------
    		else
    		{	
    			self.str_CurrentPlist = @"MENU_1_1";		
    		}
    }
    
    This leads me to the conclusion that the problem might have to do with the way I concat the string with the row-number. Could it be that the format of the string is altered, or is there something more nefarious lurking inside this code?
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Your property is set to assign. This means that when you do:

    Code:
    self.str_CurrentPlist = [self.str_CurrentPlist stringByAppendingString:temp];
    
    you assign the pointer but do not retail the object. As stringByAppendingString: returns an autoreleased string you have an issue. The normal thing to do would be to have the property set to retain, not assign.
     
  3. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #3
    So once I use the string for the first time it removes itself when set to assign, and when using retain it persists in memory and is accessible multiple times? Am I understanding this correctly?

    Anyway, it works flawlessly now - thanks a lot :)

    P.S. Nice to see someone supporting the free press.
     
  4. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #4
    I am making an educated guess by your verbiage that you don't understand retain/release memory management. As such, you should read this:
    http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/MemoryMgmt.html

    Once you understand ownership this will make a lot more sense. With assign you were getting a pointer to an object you didn't own. Trying to utilize an object you don't own is verboten.

    -Lee
     
  5. kainjow, Jan 13, 2011
    Last edited: Jan 13, 2011

    kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #5
    BTW, are you sure you want to be passing n_row as a pointer? Maybe that should not be a pointer and just the value itself, since NSInteger is not an object, you only need to pass by reference when modifying its value.
     
  6. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #6
    So the way the code is written, the string will append a number composed from the decimal integer value of the pointer to n_row?
     
  7. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #7
    Ok, the fog regarding the topic of memory management is starting to clear (I think):

    "copy" : stores a copy of the actual property, but manipulating that copy will not manipulate the actual property (the original).

    "retain" : tells the compiler that the calling instance want to claim ownership of that property and retain it in memory for as long as the instance is alive (or until it is released).

    "assign" : now why would you use assign when all it seems to do is create a property that you can't manipulate? Is it for read-only data, ie. a way to create constants?


    Yes, you're probably right - I should only need the value since I only read it in that function and have no intention of manipulating the original.
     
  8. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #8
    Your verbiage is a little rough (there's a LOT of terminology if you haven't programmed before). The first two attributes you listed only really refers to properties that are pointers to objects.

    With copy when you set the property a copy message is sent to the object you pass in. This gives you a new object you own, and you are no longer affected by what happens to the original that was passed in. When you set the property and it has a previous value, release is sent to the old object relinquishing ownership.

    With retain, when an object is passed in it is sent a retain message claiming ownership. This is going to result in sharing the object so changes you make will be reflected other places the object is used, and vice versa. When a new value is set release is sent to the old value relinquishing ownership.

    Assign is not meant for objects. A few things would work (NSString literals) but for the most part this flies in the face of retain/release memory management. You should use assign for primitives like int, double, NSInteger, etc. For objects you need to pick one of the other options.

    -Lee
     
  9. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #9
    That clears the last fog from my brain - thanks a lot :)

    Well, I've been programming before in C# and Java, and in that case I could easily migrate concepts from one language to another. But Obj-C is an ENTIRELY different creature. Perhaps my problems with wrapping my head around Obj-C (other than being a bit daft ;) ) is a case of "learning an old dog to sit..". Without any previous knowledge of programming I wouldn't have such a hard time redefining in my head how to program, I guess :)
     
  10. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #10
    I would dispute this point. There are some cases where it would be better for one object not to own another one yet still maintain a reference to it. This is described in reference-counted memory management as a "weak reference". It does seem a lot safer for every object to retain and release all of its object pointers, but I think there are times when using weak references makes sense. Either technique calls for due diligence in object management..
     
  11. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #11
    I guess I consider this a case where I'd say "you'll figure it out when you need it". In this very thread an error was made involving using assign for an object. For the OPs current purposes, assign isn't what they are looking for. Sometimes one has to lie for the sake of simplicity, and months or years later apologize when the lie is uncovered because a need for more advanced techniques has arisen.

    I don't dispute your point, but my original assumption was a newcomer to programming not just to Objective-C. Maybe the OP has dealt with and understands the need for weak references. I erred on the side of simplicity.

    -Lee
     

Share This Page