views:

79

answers:

2

Hi , I am a newbie to the iphone app world. So I thought I try my luck with a calculator app. Unfortunately I am running into an issue where if I press a third key in the calculator the app crashes. Sometimes I get this error EXC_BAD_ACCESS. Here is a code in my CalculatorViewController.m file.

#import "CalculatorViewController.h"

@implementation CalculatorViewController

@synthesize screenText;

- (IBAction)buttonPressed:(id)sender {
    NSString *title = [sender titleForState:UIControlStateNormal];
    [self collect:title];
}

- (void)collect:(NSString *)digitz {
    NSString * newText = nil;
    if ([digitz isEqualToString:@"+"]) {
        [self add:result];
        big_digit = nil;

    }
    else if ([digitz isEqualToString:@"+"]) {
        [self sub:result];
    }
    else if ([digitz isEqualToString:@"x"]) {
        [self multiply:result];     
    }
    else if ([digitz isEqualToString:@"="]) {
        [self equate:result];       
    }
    else {
        if (big_digit != nil && [big_digit isEqualToString:@"0"] == FALSE)
            big_digit = [big_digit stringByAppendingFormat:@"%@",digitz];
        else
            big_digit = (NSMutableString *) digitz;
        result = (int) big_digit;
        newText = [[NSString alloc] initWithFormat:
               @"%@",big_digit];    
    }

    screenText.text = newText;
    [newText release];  
}


- (void)add:(int)res {
    NSString * newText = nil;
    ans = ans + res;
    newText = [[NSString alloc] initWithFormat:
               @"%@",ans];

    screenText.text = newText;
    [newText release];
}

Can anyone spot an obvious issue here. Here is the respective header file too.

#import <UIKit/UIKit.h>

@interface CalculatorViewController : UIViewController {
    UILabel *screenText;
    int number;
    int result;
    int ans;
    //NSString *big_digit;
    NSMutableString * big_digit ;
}
@property (nonatomic, retain) IBOutlet UILabel *screenText;
- (IBAction)buttonPressed:(id)sender;
- (void)collect:(NSString *)digitz;
- (void)add:(int)num;
- (void)sub:(int)num;
- (void)multiply:(int)num;
- (void)equate:(int)num;

@end
+2  A: 

Well, you probably don't want to just cast a string to an integer (ala (int)big_digit). Instead you want to use [big_digit integerValue];

I think what is happening is that your big_digit property is not retained. In this line, you just assign a string to it that is autoreleased:

big_digit = [big_digit stringByAppendingFormat:@"%@",digitz];

On the next pass through, big_digit is != nil, but [big_digit isEqualToString:@"0"] == FALSE fails because big_digit now points to an invalid memory location.

What you want to do is make big_digit a property in your interface, like so...

@property (nonatomic, retain) NSMutableString *big_digit;

I know reading docs sucks, but looking at your code I think you would really find reading through this useful. Memory management in objective c is quite a bit different from regular old C. http://developer.apple.com/iphone/library/documentation/cocoa/conceptual/memorymgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW1

DougW
By using [big_digit integerValue]; instead of (int)big_digit , the app crashes at the press of the first button.After reading the link you posted , it looks like using the @property (nonatomic, retain) NSMutableString *big_digit;should keep my big_digit value till I decide to release. And I am using it as you suggested. However the code still crashes after the push of the third number button.
Justin
Justin: Nonetheless, `[big_digit integerValue]` is correct and `(int)big_digit` is wrong. The latter does not attempt to interpret the string at all; it converts the string object's pointer—its address—to the `int` type, which means you're assigning *the address of the string object* to `result`. What you mean to do is to assign the number that the string represents to `result`, and you need to send the string object an `integerValue` message to obtain that number.
Peter Hosey
DougW, Justin: You also need to use `self.big_digit` to trigger the retain. Without `self.`, you are assigning directly to the instance variable, not assigning to the property. Only assigning to the property triggers whichever memory-management policy (`retain`, `copy`, or `assign`) you set for it; assigning to the instance variable is *just* an assignment to a variable, nothing more, so the string object is not retained when you do that, regardless of how or whether the property is declared.
Peter Hosey
Peter is correct. My answer addresses the specific problem you are experiencing, but the reason I linked that document is that I see a number of basic structural problems with your code. These types of problems can't really be addressed via question/answer, and I think you really need to walk through some of the basics of Objective C. It just takes a little reading to understand how the patterns differ from C.
DougW
Thanks guys. I finally got it working.
Justin
Please mark this as answered!
Nic Hubbard
@Nic Hubbard Yeah when you answer questions from people with no rep, you just don't always get accepted. Not their fault really, they don't know. I think SO needs to put some thought into automatic acceptances, or acceptance votes after X time, or something.
DougW
Doug, yeah, I agree. It seems like a bad system. So many posts that do have answers, but they are not marked.
Nic Hubbard
A: 

In your format strings, you're doing this:

newText = [[NSString alloc] initWithFormat:@"%@", ans];

But according to your @interface, ans is an integer. So that line should read:

newText = [[NSString alloc] initWithFormat:@"%d", ans];

since %d is the format specifier for an integer.

Jeff Kelley
@Jeff Kelley, if their is the problem of type casting, i will suggest you please try atoi() function.
RRB
Rajendra Bhole: `atoi` takes a C string. It will not work on an NSString. Moreover, the goal is not to interpret a string (in any form) as an integer; it is to create a string representing an integer.
Peter Hosey