Why do I get EXC_BAD_ACCESS? - objective-c

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.

Related

Understanding Objective-C method value passing

Lets say I have in viewDidLoad:
NSMutableArray *entries = [NSMutableArray array];
[self doSomethingWithArray:entries];
NSLog(#"%#", entries);
Then in method I have:
- (void)doSomethingWithArray:(NSMutableArray *)entries
{
// create some custom data here, lets say - Something *something...
[entries addObject:something];
}
How is it possible that entries (one at the top) now (after method is finished) contain object something, since object "something" is not added to property or instance variable, and nslog will log class "Something" ? And doSomethingWithArray doesn't return anything since its "void".
I have encountered this for first time and dunno if there is any name of this appearance ?
I have seen this for second time in some examples and really dunno how its done.
If anyone could explain this a bit whats happening here I would be very very grateful.
Thank you a lot.
Because Objective-C instances are passed by reference (as you can tell by the * pointer syntax). You basically pass the address of the array to the doSomethingWithArray: method. In that method you add something to the array referenced by that address. And of course once the method returns, your array will contain that new object.
When you are adding the something object to the array, the array always retains it i.e it maintains copy of the Something object.
So NSLog prints the something.
Hope that helps.

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

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.

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];

iPhone simulator app crashes when appending a string

I'm a complete novice, so I'm probably missing something really easy, but I can't get my string appending to work. I add the 3rd character to typedDigit & it crashes - the method is called fine and typedDigit will get to 2 characters long. I think everything is declared properly in the header file. Code is -
-(IBAction)digitPressed:(UIButton *)sender {
NSString *digit = [[sender titleLabel] text]; // in this case, "0" - "9"
if (userIsInMiddleOfTyping) { // typedDigit is already at least 1 character long
typedDigit = [typedDigit stringByAppendingString:digit];
} else { // first character of typedDigit
typedDigit = digit;
userIsInMiddleOfTyping = YES;
}
}
Many thanks for any help!
Without the stack trace of the crash, it's hard to know the cause, but my guess will be that typedDigit is being autoreleased before the next call of your digitPressed function. stringByAppendingString: returns an autoreleased object, so you'll need to retain it if you want it to hand around past the next autorelease pool flush. For a direct fix, try something like...
if (userIsInMiddleOfTyping) {
typedDigit = [[[typedDigit autorelease] stringByAppendingString:digit] retain];
} else {
typedDigit = [digit retain];
...
More than this, you'll need to make sure you release typedDigit at some point after the typing is over, and you're finished with it.
You'll want to make sure digit is not NULL when trying to appending it. Also there is no mention of typedDigit's initialization, so if it is a garbage pointer or otherwise poorly-initialized, you'll crash when you try to manipulate it.
I think you probably have an ownership problem. If typeDigit is an object instance variable, you should be setting it with a setter method. In any case, you never call "retain" on the strings you want to keep around, so they are probably deallocated behind your back between method calls.

Is if (variable) the same as if (variable != nil) in Objective-C

I am getting a EXC_BAD_ACCESS (SIGBUS) on this line in my iPhone project:
if (timeoutTimer) [timeoutTimer invalidate];
The thing that has me stumped is that I don't understand how that line could crash, since the if statement is meant to be checking for nil. Am I misunderstanding the way Objective-C works, or do line numbers in crash statements sometime have the wrong line in them?
Just because a variable is set to a value other than nil doesn't mean it's pointing to a valid object. For example:
id object = [[NSObject alloc] init];
[object release];
NSLog(#"%#", object); // Not nil, but a deallocated object,
// meaning a likely crash
Your timer has probably already been gotten rid of (or possibly hasn't been created at all?) but the variable wasn't set to nil.
I just ran into a similar issue, so here's another example of what might cause a check such as yours to fail.
In my case, I was getting the value from a dictionary like this:
NSString *text = [dict objectForKey:#"text"];
Later on, I was using the variable like this:
if (text) {
// do something with "text"
}
This resulted in a EXC_BAD_ACCESS error and program crash.
The problem was that my dictionary used NSNull values in cases where an object had an empty value (it had been deserialized from JSON), since NSDictionary cannot hold nil values. I ended up working around it like this:
NSString *text = [dict objectForKey:#"text"];
if ([[NSNull null] isEqual:text]) {
text = nil;
}
They should be the same. Perhaps the line number is in fact incorrect.
Look for other possible errors near that in your code and see if you find anything.