Reputation: 15
I have a string (currently defined in my .h file) that I'd like to fill and reuse in my .m file.
Here's the setup:
Here's some code:
/* Modal_TestAppDelegate.h */
// in the @interface block //
@public
NSString *countOfMatches;
// in the main area of the .h //
@property (nonatomic, readwrite, reatain) NSString *countOfMatches;
/* Modal_TestAppDelegate.m */
@synthesize countOfMatches;
-(void)applicationDidFinishLaunching:(UIApplication *)application{
... other code ...
self.countOfMatches = [[NSString alloc] initWithFormat:@"0"];
}
-(void)updateButtonClicked:(id)sender{
countOfMatches = @"1";
NSLog(@"countOfMatches is now: %@",countOfMatches);
}
-(void)readButtonClicked:(id)sender{
NSLog(@"I wonder what countOfMatches is set to now? %@",countOfMatches); // CRASH!
}
the "readButtonCicked area is where I'm crashing - it looks like I can't read the countOfMatches string anymore.
Any ideas on how I can simply reuse a "variable" throughout a single class (if I'm calling the .m implementation a "class" correctly - this is my first attempt and I'm kinda ripping pages out of the several Xcode and iPhone SDK books I have).
Thanks!
Upvotes: 0
Views: 617
Reputation: 1338
The property has a copy characteristic, so it's making a copy of whatever's assigned, which in turn has the characteristic of retain (the copy it makes has a retain count of 1), so it doesn't matter if it's a string-literal or not.
But here's a slightly off-topic issue: if you're going to be mutating the value at all, why not store it as an NSInteger or NSUInteger?
If you're getting an NSString from somewhere else, just use the NSString method -integerValue and store the number.
And then any time you needed countOfMatches
as a string, use NSNumber
to get the value into a string form on the fly. This will also have the added benefit of gaining you localized string values. Assuming that self.countOfMatches
is now an NSInteger:
NSString* countOfMatchesStr = [[NSNumber numberWithInteger:self.countOfMatches] descriptionWithLocale:[NSLocale currentLocale]];
Any good Cocoa or Cocoa Touch application should be internationalizable from the start, whether or not you intend to make it available in languages other than the initial language you're writing it in.
That means doing the following, at minimum:
whenever you create a new Xcode project, select each xib file, get info on it, click the General tab and at the bottom of the pane, click the button Make File Localizable. It's better to do this before you import the project into version control because it moves the xib file from the project level into a subfolder called XXXX.lproj, where XXXX is the language code of the language you're working in.
Never put user-facing string-literals into your source code! Create a .strings file: create a new file. When the template window comes up, in the Mac section choose Resource, then .strings file. Name the file Localizable.strings and save it to your project. Then be sure to follow the steps in the last bullet point to actually make it localizable.
for all those string-literals that you DID put into your source code, wrap them in calls to NSLocalizedString(@"My Button Label", @"an optional comment, use empty string if no comment");
I'll leave it to you to read more about how to format the contents of .strings files.
Upvotes: 0
Reputation: 36389
Your problem is occurring when you set countOfMatches to the string literal @"1"
in updateButtonClicked:
String literals are autoreleased, which means that when this pass of the run loop is complete, it will receive the -release
message.
The run loop completes when your top-most method is finished, which means that your updateButtonClicked:
method will work fine, but when it's complete, countOfMatches will be pointing to garbage memory.
If you push your read button after the update button, your application will try to find an object in the memory that countOfMatches is pointing to and will find garbage instead. This is why you're application is crashing.
Two possible solutions exists:
self.countOfMatches = @"1";
countOfMatches = [@"1" retain];
Upvotes: 0
Reputation: 27601
You should set your NSString
property to copy
, not retain
. (More here)
@property (nonatomic, readwrite, copy) NSString *countOfMatches;
You're also leaking memory on this line
self.countOfMatches = [[NSString alloc] initWithFormat:@"0"];
It could be
self.countOfMatches = [[[NSString alloc] initWithFormat:@"0"] autorelease];
or even better:
self.countOfMatches = [NSString stringWithFormat:@"0"];
or even best (and really, what it should be):
self.countOfMatches = @"0";
There's no sense using any of the "format" methods of NSString
-- you're just setting it to a static string.
Upvotes: 4