views:

122

answers:

4

(programming in iPhone objective-C)

I have a class level NSString* that I create, add property(nonatomic,retain) and synthesize code for and I can modify the string endlessly with stringByAppendingString functions and display the string using NSLog just fine. All of this is done in a subclass, overridden viewDidLoad function. When I try to access the same variable from the cellForRowAtIndexPath fuction when determining what to display in the cell of a tableView, the program crashes. Anyone have any clues?

Related Code:

@interface InfoViewController : UITableViewController {
    NSString *shipAddr;
}
@property (nonatomic,retain) NSString *shipAddr;

@synthesize shipAddr;

VIEWDIDLOAD:

shipAddr = [[[NSString alloc] initWithString:@""] retain];

**CRASHES HERE:

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

**

A: 

Try putting an NSLog statement at the beginning of your viewDidLoad and tableView:cellForRowAtIndexPath: methods. If the latter is running first, then it'll try to access the variable before it's been created.

If you know what shipAddr should be early enough, I'd put the initialization in your init method.

Jeff Kelley
+2  A: 

You're actually double-retaining the original string, which leaks it, but that's not the cause of your crash.

You're crashing because stringByAppendingString: returns an autoreleased string. So it doesn't matter how many times you retain the original; every time you call stringByAppendingString: (or any of the other stringByWhatever methods) you get a new string that has a limited lifetime.

For your code, I would suggest simply always assigning to self.shipAddr, and just assigning @"" to the string to begin with. The self.shipAddr version will handle memory management for you automatically.

Brent Royal-Gordon
A: 

I assume you do realize that the @synthesize statement goes in the implementation file and not the header.

Also in viewDidLoad, if you must do that, I think you can just do:

self.shipAddr = @"";

Since the property is already defined to retain the passed argument.

One last thing I notice is that, I believe the call to NSLog should be like so:

NSLog(@"%@", shipAddr);

The function's format is like so: void NSLog(NSString *format, ...);

And yes, as Brent mentioned, because stringByAppendingFormat returns an auto-released string, it probably 'disappears' before you can ever see it in your other method. So you should use this:

self.shipAddr = [shipAddr stringByAppendingFormat: blah blah];

Since this uses the property for shipAddr, which, as you defined, retains the passed argument and takes care of the problem.

Jorge Israel Peña
A: 

Are you sure that viewDidLoad is called before tableView:cellForRowAtIndexPath:? It sounds like the string is either uninitialized or released when you reference it within that function. Given that you're allocing and retaining the string in viewDidLoad (you actually don't need a retain there), I'd say it hasn't been initialized yet!

Ben Gotow