user815362
user815362

Reputation:

Objective C Class instance properties deallocating in UITableViewController

Working on an iPhone app where I have a class instance that is defined as a global and initialized in in ViewDidLoad for a UITableViewController.

When it gets to cellForRowAtIndexPath, the instance properties are deallocated and appear as in the debugger.

The properties are being loaded from the database.

Foo.h

NSString *prop1;

@property(nonatomic, retain)NSString *prop1;
-(void)shouldLoadProperties;

Foo.m

@synthesize prop1;

-(void)shouldLoadProperties {
    <FMDatabase stuff here>

    FMResultSet *rs = [self executeQuery:sql];
    prop1 = [rs stringForColumn:@"col1"];  //loads db value "Test" into prop1
}

The tableview controller:

TestTableViewController.h

Foo *foo;

TestTableViewController.m

-(void)viewDidLoad {
   foo = [[[Foo alloc] init] retain];
   [foo shouldLoadProperties];

   //Breakpoint here shows that foo.prop1 is set to "Test"

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

   //foo is is still allocated, but foo.prop1 has been 
   //deallocated;  shows as <freed object>  

  NSLog(@"Prop 1 is %@", foo.prop1);  //throws exception


}

I'm not releasing foo, so why would the properties deallocate themselves? Am I missing something in Foo to hang onto the properties until the instance is released?

UPDATE

I found that by adding retain when populating the property from the database, that the data holds:

 prop1 = [[rs stringForColumn:@"col1"] retain];

Is this correct or am I missing something else?

Upvotes: 1

Views: 180

Answers (1)

Cowirrie
Cowirrie

Reputation: 7226

The problem here is that you're not using prop1 as a property, but as a variable within your class. You can and should give these different names. It's customary to put an underline at the start of the variable name:

foo.h

NSString *_prop1;

@property(nonatomic, retain)NSString *prop1;
-(void)shouldLoadProperties;

foo.m

@synthesize prop1 = _prop1;

Now, to actually use your properties, use the getters and setters. This will retain your value and release it when appropriate.

[self setProp1:[rs stringForColumn:@"col1"]];  //loads db value "Test" into prop1

and

self.prop1 = [rs stringForColumn:@"col1"];  //loads db value "Test" into prop1

are both valid and equivalent to each other.

_prop1 = [rs stringForColumn:@"col1"];  //loads db value "Test" into prop1

Will lead to crashing and other bad behavior.

Your update will prevent the crash, but will leak memory if you do it more than once.

Upvotes: 1

Related Questions