views:

1259

answers:

4

I've written an Objective-C class and I'm using a shared instance of it across several of the views in my iPhone project. Its member variables include bools, ints, NSStrings and one NSNumber. The shared instance seems to work just fine across the scope of my application, except for the NSNumber which the debugger tells me is "out of scope" once the shared instance has been accessed for the 2nd or subsequent times.

Here's a quick overview of what I'm doing...

// UserData.h
@interface UserData : NSObject {
    TaxYears selectedTaxYear;
    NSNumber *grossWage; // <--- this is the troublesome member

// ...

    NSString *other;
    int age;

}
+ (UserData *)getSharedUserData;

@end

// UserData.m
#import "UserData.h"

@implementation UserData

static UserData *sharedUserData = nil;  // Points to the shared object

+ (UserData *)getSharedUserData {
    if(sharedUserData == nil) {
     sharedUserData = [[UserData alloc] initWithTaxYear:0];
     [[NSNotificationCenter defaultCenter]
      addObserver:sharedUserData
      selector:@selector(doTerminate:)
      name:UIApplicationWillTerminateNotification
      object:nil];
    }
    return sharedUserData;
}

- (id)initWithTaxYear:(TaxYears)theTaxYear {
    if ((self = [super init])) {

    }
    return self;
}
- (void)updateGrossWage:(NSNumber *)theGrossWage {
    grossWage = theGrossWage;
}
- (NSNumber *)getGrossWage {
    return grossWage;
}
// ...
@end

So it is accessed in one view like this:

UserData *userData
userData = [[UserData getSharedUserData] retain];

And in another view in the same way. But the second time it is accessed, the grossWage member is out of scope, but everything else is fine - this is why I'm stumped. Any ideas?

+3  A: 

Why do you write the grossWage accessors (updateGrossWage and getGrossWage) by hand? And are you sure you simply want to simply assign the given gross wage instead of retaining or copying it? This way when the caller gets rid of his gross wage instance you will end up with released gross wage in the userData object:

NSNumber grossWage = [[NSNumber numberWithInt:12] retain];
[userData updateGrossWage:grossWage];
[grossWage release];
// Now userData’s grossWage points to released object.

This could be the cause of the problem. If not, I’d suggest posting a smaller piece of complete example code – without the notification stuff and with the calling context.


P.S. Such shared objects as your UserData are usually bad for your design (= leading to pain in code), see for example this article by Miško Hevery and other articles on his blog.

zoul
I wrote the accessors as I anticipated at the beginning that I might want to perform casting or other manipulation on the members... but now it looks like I could do away with them for simplicity's sake. I just tried bypassing the accessor method, defining grossWage as a @property and setting it directly and it seems to have done the trick... many thanks! If it turns out that this was not the problem I'll be back. Looks like I need to read up some more on memory management.
moigno
A: 

Following up on @zoul's point...

I would declare that grossWage is a property, and synthesize the getters and setters. I think that setter is the source of your problem.

// in UserData.h
@interface UserData : NSObject {
    NSNumber *grossWage; 
}

@property (nonatomic, retain) NSNumber *grossWage; 



// in UserData.m
#import "UserData.h"

@implementation UserData
@synthesize grossWage;

// then do NOT create getters and setters for grossWage

See if that does not clear it up.

mmc
+2  A: 

The reason you're having trouble is not because you should or shouldn't be using a property, but because you're not following memory management rules. NSNumber is an object, and should be retained in your setter. Changing it to a property will fix the immediate problem because Objective-C is handling the work for you, but you should still review memory management because it's 100% certain you're going to continue to have problems until you're comfortable with it.

Marc Charbonneau
A: 

It sounds stupid but check for division by zero. I had the same error and the reason was a division by zero.

cocoafan