Search code examples
objective-cmacosmemory-managementmemory-leakssubclassing

Information in text fields do not get retained objective c


This is a simple program that takes two numbers inputed by the user in two separate text fields and adds them together when the 'Add' button is clicked. The way I have done this is by subclassing NSTextField into a class called MyTextField. I believe my error has something to do with memory leaks, but being an inexperienced programmer, I'm not quite sure how to deal with allocating and deallocating memory.

The problem is: When I click the Add button, it works perfectly. However, when I click it again, it does not show the correct amount. It keeps taking my inputs as nil and outputting 0. I have attached my code.

Note: I know that this is much more complicate than it needs to be! I am simply showing a simpler version of a much more complicated program that displays the exact same error.

MyTextField.h

#import <Cocoa/Cocoa.h>

@interface MyTextField : NSTextField

@property (strong) NSString* number;
@property double dblNum;
-(id)initWithNumber:(NSString *)number;
-(NSString *)getNumber;
-(void)setNumber;
-(double)getDblNum;
-(void)setDblNum;
-(double)calcSum:(MyTextField *)other;
-(NSString *)description;
@end

MyTextField.m

#import "MyTextField.h"

@implementation MyTextField

-(id)initWithNumber:(NSString *)number{
    self = [super init];
    if (self) {
        if ([number length] > 0){
            _number = number;
        }else{
            _number = @"0";
        }
        [self setDblNum];
    }
    return self;
}
- (id)init {
    return [self initWithNumber:[self getNumber]];
}
-(NSString *)getNumber{
    return _number;
}
-(void)setNumber{
    _number = [self stringValue];
}
-(double)getDblNum{
    return _dblNum;
}
-(void)setDblNum{
    _dblNum = [_number doubleValue];
}
-(double)calcSum:(MyTextField *)other{
    return [self getDblNum] + [other getDblNum];
}
- (NSString *)description{
    return [NSString stringWithFormat: @"Number: %f", _dblNum];
}
@end

ViewController.h

#import <Cocoa/Cocoa.h>
#import "MyTextField.h"

@interface ViewController : NSViewController

@property (strong) IBOutlet MyTextField *valueOne;
@property (strong) IBOutlet MyTextField *valueTwo;
@property (strong) IBOutlet NSTextField *answer;
- (IBAction)btnAdd:(id)sender;

@end

ViewController.m

#import "ViewController.h"
#import "MyTextField.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
}

- (IBAction)btnAdd:(id)sender {
    _valueOne = [[MyTextField alloc] initWithNumber:[_valueOne stringValue]];
    _valueTwo = [[MyTextField alloc] initWithNumber:[_valueTwo stringValue]];
    double ans = [_valueOne calcSum:_valueTwo];
    _answer.stringValue = [NSString stringWithFormat:@"%.2f", ans];
}
@end

P.S. Sorry for the annoying amount of code. Thanks!


Solution

  • Your btnAdd: is where the problem is.

    - (IBAction)btnAdd:(id)sender {
        _valueOne = [[MyTextField alloc] initWithNumber:[_valueOne stringValue]];
        _valueTwo = [[MyTextField alloc] initWithNumber:[_valueTwo stringValue]];
        double ans = [_valueOne calcSum:_valueTwo];
        _answer.stringValue = [NSString stringWithFormat:@"%.2f", ans];
    }
    

    Each time the button is tapped, you're recreating both MyTextField instances. Instead, you simply need to get & set the values from your existing valueOne and valueTwo outlets, like:

    - (IBAction)btnAdd:(id)sender {
        double value1 = [_valueOne.text doubleValue];
        double value2 = [_valueTwo.text doubleValue];
        double ans = value1 + value2;
        _answer.stringValue = [NSString stringWithFormat:@"%.2f", ans];
    }
    

    Obviously, you need to check the validity of the valueOne and valueTwo text strings.

    You really don't need a MyTextField subclass, because it's not doing anything except converting strings to doubles (and vice versa).