Saving [NSTextField stringValue]... variable is cleared when my window closes? - objective-c

So I grab the username from the field, save it in an NSString variable:
loggedInUser = [usernameField stringValue];
[loginWindow close];
Later, I try to access that loggedInUser data:
NSLog(#"Logged in User:%#", loggedInUser);
This often, but not always, gives an error:
Program received signal: "EXC_BAD_ACCESS". // Summary displays "{...}" for the value
The loggedInUser NSString gets cleared? What happened? (I never modify this value myself).
My only thought is that I am somehow saving the continued value of the NSTextField in the NSString. Then, when I close the window, that value is cleared.
Is that what's happening? How do I save that Textfield value in a safe way for continued use?

Ahhh, I just realized what is going on.
When you close your window (and it likely gets released), the string that you assigned to your object's NSString variable is autoreleased as well.
You need to explicitly retain it.
Or, more to the point, do this:
loggedInUser = [[NSString alloc] initWithString: [usernameField stringValue]];
or:
loggedInUser = [[usernameField stringValue] copy];
don't forget to release loggedInUser when your dealloc method is called (assuming you're not using ARC here).

Another solution would be to store the string in a property rather than an instance variable. You could declare the property as strong (or retain) or copy, and you would then own the string (or a copy of it).
You mention that the variable “is cleared” when the string dies, but in fact that is not the case. The variable is not cleared, which is the cause of the crash: It still holds the pointer to a now-dead object. Keeping it alive with strong or copy is one solution, but another option, if you migrate to ARC, would be to declare the property as weak. Then, on Mac OS X 10.7 and later, the property will be cleared (set to nil) as soon as the string dies.

Related

NSString allocation and initializing

What is the difference between:
NSString *string1 = #"This is string 1.";
and
NSString *string2 = [[NSString alloc]initWithString:#"This is string 2.];
Why am I not allocating and initializing the first string, yet it still works? I thought I was supposed to allocate NSString since it is an object?
In Cocoa Touch,
-(IBAction) clicked: (id)sender{
NSString *titleOfButton = [sender titleForState:UIControlStateNormal];
NSString *newLabelText = [[NSString alloc]initWithFormat:#"%#", titleOfButton];
labelsText.text=newLabelText;
[newLabelText release];
}
Why do I not allocate and initialize for the titleOfButton string? Does the method I call do that for me?
Also, I'm using XCode 4, but I dislike iOS 5, and such, so I do not use ARC if that matters. Please don't say I should, I am just here to find out why this is so. Thanks!
The variable string1 is an NSString string literal. The compiler allocates space for it in your executable file. It is loaded into memory and initialized when your program is run. It lives as long as the app runs. You don't need to retain or release it.
The lifespan of variable string2 is as long as you dictate, up to the point when you release its last reference. You allocate space for it, so you're responsible for cleaning up after it.
The lifespan of variable titleOfButton is the life of the method -clicked:. That's because the method -titleForState: returns an autorelease-d NSString. That string will be released automatically, once you leave the scope of the method.
You don't need to create newLabelText. That step is redundant and messy. Simply set the labelsText.text property to titleOfButton:
labelsText.text = titleOfButton;
Why use properties? Because setting this retain property will increase the reference count of titleOfButton by one (that's why it's called a retain property), and so the string that is pointed to by titleOfButton will live past the end of -clicked:.
Another way to think about the use of retain in this example is that labelsText.text is "taking ownership" of the string pointed to by titleOfButton. That string will now last as long as labelsText lives (unless some other variable also takes ownership of the string).

NSString being released even after being retained

I have an NSString that I've retained, and the only place I release it is in the dealloc method. For some reason, however, later in the program when I try to reference it (its length, specifically), I get a crash, saying [CFString length]:message sent to deallocated instance 0xff32c50.
I explicitly retain the string earlier in the program. Is there any reason why this would be happening? Any help is appreciated.
The string, entityParameter, is declared in the header, and defined later.
Here is some of the code:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
The place where I'm getting the crash looks like this:
if([entityParameter length] != 0 && entityParameter != nil)
{
return;
}
I have an NSString that I've retained,
and the only place I release it is in
the dealloc method. For some reason,
however, later in the program when I
try to reference it (its length,
specifically), I get a crash, saying
[CFString length]:message sent to
deallocated instance 0xff32c50.
Obviously, it isn't retained, then.
If by "retained" you mean "assigned to a property", are you doing:
self.prop = [NSString ...];
Or:
prop = [NSString ...];
Because the former will retain (if the property is declared as retain) whereas the latter will not. Note that NSString properties should generally be declared copy, but that is orthogonal to the question).
If your code is as written:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
And you really do only release it in dealloc, then make sure your containing object hasn't already been deallocated. That may be happening. Or it might be that you've leaked the string reference somewhere and spuriously deleted it without a retain.
Using Zombie detection in instruments with "track retain/release events" (or whatever it is called) should show you every last retain/release event on the object, including the one the blew up.

objective-C: simple question about copy/retain NSString

If I set a NSString as property
#property (copy) NSString* name;
I always want to use (copy), so that if its value change, all object with such string still have the old value (as specifiedhere).
However, what happens if my NSString is not a class property, but it is just declared in the code ? Is in that case retained or copied everytime I assign a new value ?
thanks
It depends on how you declare it. You should read the documentation on memory management. Basically the rules are:
NSString *aString = [NSString stringWithString:#"Hello"];
NSString *bString = [NSString stringWithFormat:#"%#", #"Hello"];
In these cases, the string is not copied or retained. It is autoreleased, which means it will be automatically deallocated the next time the autorelease pool drains. You do not have to call the release method on them. (So assigning a new value will not cause it to leak.)
NSString *cString = [[NSString alloc] initWithFormat:#"%#", #"Hello"];
[cString release];
According to Objective C convention, methods that use alloc and have a retain count of one are not autoreleased, so you need to release them explicitly. Assigning a new value without releasing the old one will cause a leak.
You can also explicitly call a "copy" method or a "retain" method on a string. In either case, the new string will have a retain count of 1 and will not be autoreleased, so you will need to call the release method on it before you assign a new value.
NSString *dString = [cString retain];
NSString *eString = [cString copy];
...
[dString release];
[eString release];
If it is a property, and you use self.variableName, this will be taken care of for you (through the getters and setters which are generated with #synthesize). If you do it explicitly, you must make sure to call release on variables that you have called retain or copy on.
Edit: As some commentators below have noted, thinking about management in terms of "ownership" is usually the preferred of describing these ideas, rather than retain count.
If it's not a property and just declared in code, you need to explicitly retain or copy it, ie
NSString myString = [otherString copy];
or
NSString myString = [otherString retain];
Either way you also need to ensure it's released at somepoint.
If you're not using the property's setter, like self.name = #"foo" or [self setName:#"foo"], but rather assign the variable directly, like name = #"foo", it doesn't matter at all how the property is declared.
You have to understand that the property syntax is just a shortcut for writing accessor methods (-name and -setName: in this case). If you're not calling these methods (implicitly by setting the property), it doesn't matter how they work internally (which is what you specify by retain or copy).

Why do I get EXC_BAD_ACCESS?

I have following code, which executes on button press. At first it works as expected but second time onwards application hangs and I get EXC_BAD_ACCESS signal.
- (IBAction) comicDetailsPressed:(id)sender {
static IssueProperties *props = nil;
if (props == nil) {
props = [ComicDataParser
parseComicForUrl:#"http://dummy.com/Jan.xml"];
}
NSLog(#"%d", [props totalPages]);
totalPages.text = [NSString stringWithFormat:#"%d", [props totalPages]];
}
You didn't say what line it's crashing on, which will mean answers will have to be speculative.
You have a static pointer to a IssueProperties object, but when you assign to it, you aren't using retain. You probably should.
This is assuming that the return value from parseComicForUrl: is a IssueProperties object or a subclass.
I'm assuming that the text property is an NSString set to copy and not retain. If not, it should be.
You need to retain the object you get back from +parseComicForUrl:. Also, why don't you use an instance variable for props?
Without a lot more context, it is going to be impossible to answer for sure, but my first thought would be this:
your static IssueProperties *props would not be nil the second time around. Instead, it would have the value that [ComicDataParser parseComicForUrl] returned.
My guess is that the ComicDataParser is autoreleaseing the response, and so the second time around you have a pointer that is not nil, but is now pointing to an already released object, which is invalid.
If I am right, you need a retain somewhere.

Objective-C NSString Assignment Problem

In my Cocoa application, in the header file, I declare a NSString ivar:
NSString *gSdkPath;
Then, in awakeFromNib, I assign it to a value:
gSdkPath = #"hello";
Later, it's value is changed in the code:
gSdkPath = [NSString stringWithString:[folderNames objectAtIndex:0]];
(the object returned from objectAtIndex is an NSString)
However, after this point, in another method when I try to NSLog() (or do anything with) the gSdkPath variable, the app crashes. I'm sure this has something to do with memory management, but I'm beginning with Cocoa and not sure exactly how this all works.
Thanks for any help in advance.
EDIT: This was solved by retaining the string [gSdkPath retain].
(the object returned from
objectAtIndex is an NSString)
Are you sure? I suggest putting this in it's own temporary variable and double checking that it's not nil or invalid in some way.
Edit: If that is OK so far, do note that stringWithString returns an autoreleased object. You need to retain it if you want to use it "later".
gSdkPath = [NSString stringWithString:[folderNames objectAtIndex:0]];
[gSdkPath retain];