views:

1323

answers:

5

I'm using indexPath.row do determine in which row of my tableview I do something. The title of my cells is containing a number which should be 1 in the first row and 18 in the last row, so I have 18 rows. This works for the first 11 rows, but after that, I have numbers in the title which seem to be generated randomly! Sometimes 16, then 5, then 18, then 12... and so on. What's the problem with it/why does the indexPath.row variable behave like that?

My cellForRowAtIndexPath method:

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

static NSString *MyIdentifier = @"MyIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
    [[NSBundle mainBundle] loadNibNamed:@"myCell" owner:self options:nil];
    cell = cell0;
    self.cell0 = nil;
}
UILabel *label;
label = (UILabel *)[cell viewWithTag:1];
label.text = [NSString stringWithFormat:@"Cell %d", indexPath.row];

return cell;

}

Any more suggestions on how to solve the problem? I didn't get it working until now...

// Update with more code:

Here is how I declare the cell. It is in an XIB file (template "empty XIB") in which I just put the cell from the library in IB.

@interface myViewController : UITableViewController {

    UITableViewCell *cell0;
}

@property (nonatomic, retain) IBOutlet UITableViewCell *cell0;

Then, at the top of the myViewController.m file:

@synthesize cell0;

My cellForRowAtIndexPath method is already posted above. It is equal to the cellForRowAtIndexPath method in the SDK documentation, and in Apple's example, it seems to work.

A: 

To would be easier to answer if you give the code where you create cells for your table view.
It looks that there's a problem with reusing cells - you reuse previously created cells without setting a new value to it.

Vladimir
A: 

It sounds like you are not re-using cells but creating new ones when there are cells available. Look at the sample code for dequeueReusableCellWithIdentifier.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];
    if (cell == nil) {
     cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyCell"] autorelease];
    }

    cell.text = <your code here>;
    return cell;
}
zaph
I posted my cellForRowAtIndexPath method in the post above. I tried adding the " cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyCell"] autorelease];" line to my code, but it changed nothing.
Yassin
+1  A: 

What are you trying to accomplish with cell0?

cell = cell0;
self.cell0 = nil;

It looks like you're creating a new cell, but somehow deciding to use an old one. The real culprit looks like the code that is loading the cell actually getting assigned anywhere.

Try just this instead:

if (cell == nil) {
    cell = [[NSBundle mainBundle] loadNibNamed:@"myCell" owner:self options:nil];
}

Or perhaps:

if (cell == nil)
{
     // TODO: try to avoid view controller
     UIViewController *vc = [[UIViewController alloc] initWithNibName:@"IndividualContractWithResult" bundle:nil];
     cell = (IndividualContractWithResult_Cell *) vc.view;
     [vc release];
}
Epsilon Prime
This doesn't really work, it gives a warning "incompatible Objective-C types assigning 'struct NSArray *', expected 'struct UITableViewCell *'" and if I access the view, the app closes instantly.
Yassin
Sorry, I have access to my code again. In it I use an external NIB to load in my cells. I'll add it above so there's formatting.
Epsilon Prime
I see where cell0 is coming from now. You're supposedly reloading the entire NIB just to get a new cell0 which you then use as your cell. I wonder if you're running low on memory which is causing these earlier grabs to be freed. Then they get reused for later elements.
Epsilon Prime
I tried both examples, but they don't work and make the app close instantly after calling the TableView. I wonder why my own code does not work since it is exactly the same as in Apple's sample code here: http://developer.apple.com/iphone/library/documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7-SW31 and I don't think that they puplish sample code with problems like the one I have with my app.
Yassin
A: 

It would seem that you're incorrectly accessing a property here:

cell = cell0;
self.cell0 = nil;

Assuming that you have an instance variable named cell0, by setting it to nil, you may be releasing it before you're ready to use it.

The proper way to do this is:

cell = self.cell0;
self.cell0 = nil;

This way, if cell0 is declared as retain, you'll automatically get an autoreleased cell0 back, whereas if you reference cell0 directly (no self.), you'll get an unretained reference, which will disappear when self.cell0 = nil is called.

The advantage of using a nib-based cell here is that you can use outlets, rather than tags, to identify subviews. You've done the heavy lifting already, you might want to just add an outlet and subclass UITableViewCell to get access to the label.

Ben Gottlieb
-> outlets/tags: Yes, but I have 18 rows created from a single custom cell, and I want to access one specific label in one specific cell, so I can't use the outlets, right?-> cell0/self.cell0: This also didn't work...
Yassin
It's unclear what cell0 is. Is it an instance variable? If it's a property (which it seems to be), how is it declared? retain or assign? Without seeing the rest of your code, I can't be sure, but I think there's something amiss with the way you're re-using your cells.
Ben Gottlieb
cell0 is the UITableViewCell declared in my view controller's header file, I have it assigned to my cell (which is in an empty XIB file) in IB. It is declared as @property (nonatomic, retain) UITableViewCell ... in the .h file.
Yassin
A: 

You will need to retain and autorelease cell0, otherwise when you set self.cell0 = nil, then cell0 has no known references.

cell = [[cell0 retain] autorelease];
self.cell0 = nil;

You can also do this:

cell = self.cell0;
self.cell0 = nil;

.. Since any retain properties should implement their getters with the retain/autorelease pattern.

Jason
Both didn't work...
Yassin
See my edits for another approach...
Jason
I added some more code above... I guess that I should replace "MyViewController" in your code with the name of my view controller? I did this, and it did make the app quit as I access the view. Is it maybe a problem that my cell is in an extra empty XIB file?
Yassin
Now that I see your code and how you're using it, that definitely wouldn't be the right approach. Edited to remove that idea. Do you have the cell's reuse identifier set to "MyIdentifier" in your XIB, and the File Owner class to MyViewController?
Jason
Yes, the cell identifier is set to "MyIdentifier" and the File's Owner class to MyViewController.
Yassin
Try reading over this article: http://pegolon.wordpress.com/2008/11/15/using-uitableviewcell-with-interfacebuilder/ - it contains better examples on how to do this.
Jason
Thanks, it's working now. Had some problems with my method to assign an individual tag to it, after removing that and following your tips it worked.Have you got any idea how I could distinguish between "Button in row 1 was pressed" and "Button in row 18 was pressed"?
Yassin
In your cellForIndexPath, set `button.tag = indexPath.row` and then check `sender.tag` in the handler for the button.
Jason
I'm using it like this right now, but if I scroll up and down a bit, the tag changes again... like it was with my first problem.
Yassin
Seems to be a problem with the changing of the object's tag in general.
Yassin