I have a TableView with custom cells, some of which have images and others don't have. Everything works fine but when I start scrolling the cells aren't showing correctly (the images are placed in "wrong" cells and cut in the middle). Does anyone now how to fix this?
问题:
回答1:
The key thing to understand is that your table's cells are reused. This is done to increase the performance for scrolling because creating a new cell - which is a view - is quite expensive.
In the method cellForRowAtIndexPath, you return a cell. Either an existing cell using the dequeue method, or you create a new one. On that cell, you set all the properties of whatever it is you wish to represent.
My guess is that you are setting these properties such as image, etc. on the cell directly. Then when you scroll, that cell is reused and you see the same image again but on the wrong cell.
So, what you need is a separate index like an NSArray to maintain your model objects. That model object contains all the details of image, etc.
Let's take an example. I have an array with 10 objects, the first five of which are image "a.png" and the second five "b.png".
If I receive a callback of cellForRowAtIndexPath, I want to do as follows:
cellForRowAtIndexPath:(0,0) provide object from array a index 0, which is a.png cellForRowAtIndexPath:(0,1) provide object from array a index 1, which is a.png cellForRowAtIndexPath:(0,2) provide object from array a index 2, which is a.png cellForRowAtIndexPath:(0,3) provide object from array a index 3, which is a.png cellForRowAtIndexPath:(0,4) provide object from array a index 4, which is a.png cellForRowAtIndexPath:(0,5) provide object from array a index 5, which is b.png cellForRowAtIndexPath:(0,6) provide object from array a index 6, which is b.png cellForRowAtIndexPath:(0,7) provide object from array a index 7, which is b.png cellForRowAtIndexPath:(0,8) provide object from array a index 8, which is b.png cellForRowAtIndexPath:(0,9) provide object from array a index 9, which is b.png
Now, let's consider that in the UITableView, underneath the covers, five of the cells are being reused.
For each call above, the following happens:
cellForRowAtIndexPath:(0,1) provide object from array a index 1, which is a.png -- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.
cellForRowAtIndexPath:(0,2) provide object from array a index 2, which is a.png -- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.
cellForRowAtIndexPath:(0,3) provide object from array a index 3, which is a.png -- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.
cellForRowAtIndexPath:(0,4) provide object from array a index 4, which is a.png -- you attempt to dequeue an existing cell but it comes back "nil" so you create a new cell. You set the details of your model object.
cellForRowAtIndexPath:(0,5) provide object from array a index 5, which is b.png -- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object
cellForRowAtIndexPath:(0,6) provide object from array a index 6, which is b.png -- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object
cellForRowAtIndexPath:(0,7) provide object from array a index 7, which is b.png -- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object
cellForRowAtIndexPath:(0,8) provide object from array a index 8, which is b.png -- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object
cellForRowAtIndexPath:(0,9) provide object from array a index 9, which is b.png -- you attempt to dequeue an existing cell and it works! you can use that cell again by setting the details of your model object
Sorry for being so verbose! I hope this helps. Maybe it's worth working through a good table view tutorial. There will be many out there for sure.
回答2:
Try with changing the identifier value for your cell .
NSString* identifierStr = [NSString stringWithFormat:@"ident_%d",indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifierStr];
回答3:
You probably add images when you create the cell instances, instead of when the table view asks for a cell view. Example:
This is the right way. We set the image every time the table view asks for a cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ident"];
UIImageView *imageView;
if (cell == nil) {
cell = [UITableViewCell alloc] init ....];
imageView = [[UIIMageView alloc] init];
imageView.tag = 123;
[cell addSubview:imageView];
[imageView release];
} else {
imageView = [cell viewWithTag:123];
}
imageView.image = ...; // load image here
}
This is the wrong way. We set the image when we create the cell. This will cause cells to have wrong images when they are re-used.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ident"];
if (cell == nil) {
cell = [UITableViewCell alloc] init ....];
UIImageView *imageView = [[UIIMageView alloc] init];
imageView.image = ...;
[cell addSubview:imageView];
[imageView release];
}
}