Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

tjw09003

macrumors newbie
Original poster
Feb 11, 2010
13
0
I recently switched to mac and I am trying to write my first mac program.

I have a problem with NSMutableString's

The code is much more complex but I've narrowed it down to this type of problem.


Code:
NSMutableString* testString;

- (IBAction)sendTestValue:(id)sender{
     [txt_value setStringValue:testString];
}

- (IBAction)setTestValue:(id)sender{

     testString = @"test ";
     //[testString appendString:@"append worked!!];

}

If I uncomment the line [testString appendString:mad:"append worked!!];
and run setTestValue when I try to run sendTestValue the program crashes with "EXC_BAD_ACCESS"

Any ideas why?
 
The problem is the line

Code:
testString = @"test ";

Here, @"test" is a string literal which implicitly creates an NSString object (which is immutable). Just because you store it in a variable of type NSMutableString does not make it mutable. When you try and modify it later, you then run into problems since you can't modify an immutable string.

To fix this, try replacing that line with the following:
Code:
[testString release];
testString = [[NSMutableString alloc] initWithString:@"test "];
 
ok, so I tried this

Code:
NSMutableString* testString;

- (IBAction)sendTestValue:(id)sender{
     [txt_value setStringValue:testString];
}

- (IBAction)setTestValue:(id)sender{

     [testString release];
     testString = [[NSMutableString alloc] initWithString:@"test "];
     [testString appendString:@"append worked!!];

}

It still crashes with EXC_BAD_ACCESS :(

It crashes ONLY if I first run setTestValue
and then I run sendTestValue

ONLY THEN will it crash, when sendTestValue runs after setTestValue.

txt_value is a NSTextField by the way.
 
That error sounds like you have a memory problem somewhere. Could testString or txt_value somehow be released between the calls to setTestValue and sendTestValue? You might need to post more of your code for us to be able to help - is there more in the setTestValue method than what you've posted?
 
Code:
NSMutableString* testString;

- (IBAction)sendTestValue:(id)sender{
     [txt_value setStringValue:testString];
}

- (IBAction)setTestValue:(id)sender{

     [testString release];
     testString = [[NSMutableString alloc] initWithString:@"test "];
     [testString appendString:@"append worked!!];

}

If that's your exact code, then you're missing a closing quote in this line:
Code:
     [testString appendString:@"append worked!!];
after the !! and before the ]. I'm surprised it would compile.

If that's not your exact code, then please post your exact code. Copy and paste it, don't retype it.
 
Here's my exact code.

My first program on a mac so go easy on me, it's very unprofessional :p

Code:
#import "appControl.h"

NSString* sourcePath = @"";
NSString* elfPath = @"";
NSString* hexPath = @"";
NSString* finalCMD = @"";
NSString* execCMD = @"";
NSMutableArray* Arguments; 


@implementation appControl

- (IBAction)setCommand:(id)sender{			//--------"SET COMMAND" BUTTON------------------------------
	
	Arguments = [NSMutableArray arrayWithObjects:nil];      //---RESET ARGUMENTS
	
	execCMD = @"avr-gcc";									//---SET avr-gcc TO EXECUTE
	
	finalCMD = @"avr-gcc ";									//---RESET COMMAND STRING
	
	[Arguments addObject:									//---SET CLK FREQUENCY
		[@"-DF_CPU=" stringByAppendingString:
			[txt_freq stringValue]]];
	
	if ([deviceSelection indexOfSelectedItem] == 0) {		//---CHECK AND SET DEVICE TYPE
		[Arguments addObject:@"-mmcu=atmega8"];				
	}
	
	if ([deviceSelection indexOfSelectedItem] == 1) {		
		[Arguments addObject:@"-mmcu=atmega168"];
	}
	
	if ([deviceSelection indexOfSelectedItem] == 2) {		
		[Arguments addObject:@"-mmcu=atmega328"];
	}
	
	
	[Arguments addObject:@"-o"];							//---ADD -o FLAG
	
	[Arguments addObject:elfPath];   //<---**THIS IS WHERE IT CRASHES
	
	[Arguments addObject:sourcePath];
	
	
	
	
	//-------READ ARGUMENTS INTO finalCMD STRING
	int i;
	for(i=0;i<[Arguments count];i++){
		finalCMD = [finalCMD stringByAppendingString:[@" " stringByAppendingString:[Arguments objectAtIndex:i]]];
	}
	
	//-------SEND finalCMD STRING TO TEXT OUTPUT
	[txt_finalCMD setStringValue:finalCMD];
	
}

- (IBAction)getFile:(id)sender{
	
	
	NSString* prjName = [txt_fileloc stringValue];  //Get project name
	NSString* prjDir = @"/avr/prj/";  //Projects directory
	
	
	sourcePath = [prjDir stringByAppendingString:[prjName stringByAppendingString:[@"/" stringByAppendingString:[prjName stringByAppendingString:@".c"]]]];
	elfPath = [prjDir stringByAppendingString:[prjName stringByAppendingString:[@"/" stringByAppendingString:[prjName stringByAppendingString:@".out"]]]];
	hexPath = [prjDir stringByAppendingString:[prjName stringByAppendingString:[@"/" stringByAppendingString:[prjName stringByAppendingString:@".hex"]]]];

	
	[lbl_sourceFile setStringValue:[@"Source File: " stringByAppendingString:sourcePath]];
	[lbl_elfFile setStringValue:[@"ELF File: " stringByAppendingString:elfPath]];
	[lbl_hexFile setStringValue:[@"HEX File: " stringByAppendingString:hexPath]];
	

	
	
	
}


@end

It crashes when running setCommand after getFile
 
it's the elfPath string, I changed it back to a NSString when I was playing around with it trying to get it to work.



EDIT: It was also the sourcePath string which I changed to NSString too.
 
The problem is that sourcePath, elfPath and hexPath are created with convenience methods in getFile. This means that they are autoreleased, so by the time setCommand is run the memory for them will be deallocated. Then when you use them, the program crashes accessing this memory. You need to retain them before the end of the getFile method and release them at some later point to avoid a memory leak (I'm assuming here that you aren't using garbage collection).

If this doesn't make a lot of sense, I'd recommend reading the Memory Management Programming Guide for Cocoa.
 
How would I retain them and prevent them from autoreleasing after getFile?


EDIT:
I'll rewrite this code from scratch.


What would be a better way of creating a global NSString?
 
It's probably easiest if you read up on memory management in general, and then it should all make sense. Some more resources:

If you are developing only for Mac OS X 10.5 or later then you can use garbage collection and not have to worry about memory management. See Introduction to Garbage Collection if this is the case. If you ever want to develop for older versions of Mac OS X or for the iPhone, you'll need to know how to do memory management yourself though, so should read up on some of the links above.
 
I guess I'll start reading up on memory management.


EDIT: Thanks everyone, I got it to work.

I added [sourcePath retain];
and it works :)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.