我创建了一个UITableView
,其中包含显示Users
的单元格。在此方法-tableView:cellForRowAtIndexPath:
中添加每个单元格。每个单元格都有与特定用户相关联的内容,例如UIImageView
和UILabel
。
只要显示的单元格不超过9-10个,UITableView
就能正常工作。但是当细胞数量变得更高时,用户必须向下滚动才能查看它们,这就是奇怪的行为开始时的情况。来自第一个,第二个,第三个等的内容被添加到单元号十一,十二,十三等等。当用户然后向上滚动时,应该在11,12,13号上的内容现在位于第一,第二和第三单元格中......
我希望有人理解我的问题,并知道这里有什么问题..
这是我用户添加单元格的代码..忽略解析的东西虽然,我不认为它是相关的
- (UITableViewCell *)tableView:(UITableView *)tableview cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"SimpleTableCell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
if (tableview == commentViewTableView) {
//Ignore this
} else if (tableview == tableView) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 34, 34)];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
[cell addSubview:imageView];
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(44, 0, 160, 44)];
usernameLabel.textAlignment = NSTextAlignmentLeft;
usernameLabel.font = [UIFont systemFontOfSize:17];
usernameLabel.backgroundColor = [UIColor clearColor];
[cell addSubview:usernameLabel];
UIImageView *hitImageView = [[UIImageView alloc] initWithFrame:CGRectMake(245, 9.5, 25, 25)];
hitImageView.contentMode = UIViewContentModeScaleAspectFill;
hitImageView.clipsToBounds = YES;
hitImageView.image = [UIImage imageNamed:@"hit.png"];
[cell addSubview:hitImageView];
NSString *key = //Code to retrieve userKey
PFQuery *query = [PFUser query];
[query whereKey:@"objectId" equalTo:key];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
[[object objectForKey:@"image1"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
NSString *ageString = [[NSString alloc] initWithFormat:@"%li", (long)age];
imageView.image = [UIImage imageWithData:data];
usernameLabel.text = [NSString stringWithFormat:@"%@, %@", [object objectForKey:@"username"], ageString];
}
}];
}
}];
}
}
return cell;
}
答案 0 :(得分:1)
我通过将单元格标识符更改为唯一来解决了我的问题。我不知道这是否真的是这样做的方式,或者这是不是很好的做法,但是当我这样做时它解决了我的问题。因此,如果知道这是否会导致我可能遗失的任何其他问题,那么反馈会很好吗?
NSString *identifier = [NSString stringWithFormat:@"Cell%li", indexPath.row];
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
//My code..
}
答案 1 :(得分:0)
更改您的代码:
- (UITableViewCell *)tableView:(UITableView *)tableview cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"SimpleTableCell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
} // CLOSED PARANTHESES HERE!!!!
if (tableview == commentViewTableView) {
//Ignore this
} else if (tableview == tableView) {
// ... rest of your code here
}
}
答案 2 :(得分:0)
代码存在一些问题。一个是必须特别注意cellForRowAtIndex:datasource方法中的异步调用。另一个是细胞被重复使用,因此每次进入视图时向它们添加子视图将在子视图上堆积子视图。
让我们从异步操作开始。 @nburk正确地指出了这个问题,但是说你不能轻易做到这一点"。您可以预加载所有内容,但是用户必须等待整个表准备好才能看到任何内容。这里的一个好策略是延迟加载。
延迟加载取决于缓存加载结果的位置。因此,让我们的数据源数组成为可变字典的数组,如下所示:
@{@"user": aPFUser, @"image": aUIImage };
预取用户是有意义的,否则,你甚至不知道你有多少,所以,在viewWillAppear:
// setup your model as @property(strong,nonatomic) NSMutableArray *users;
PFQuery *query = [PFUser query];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// build the datasource
self.users = [NSMutableArray array];
for (PFUser *user in objects) {
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:
@{ @"user": user };
];
}
[self.tableView reloadData];
}
}];
现在,在cellForRowAtIndexPath中执行此操作:
NSMutableDictionary *userDictionary = self.users[indexPath.row];
// in the lazy pattern, if the model is initialized, we're done
// start by assuming the best
imageView.image = userDictionary[@"image"];
// but the image might be nil (it will start out that way) so, load...
PFQuery *query = [PFUser query];
[query whereKey:@"objectId" equalTo:key];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
[[object objectForKey:@"image1"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
// this is the important part: this code doesn't run when the rest
// of the method runs. It happens later, when the request completes
// so don't assume anything about the state of the table. Instead
// treat the table like you would in other view controller methods
userDictionary[@"image"] = image;
// don't fool around with cell (it might be reused). Instead
// just tell the table to reload this row
[tableView reloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}];
}
}];
下一次该行滚动到视图中时,来自异步请求的数据将缓存在您的用户词典中。
问题二更简单:代码无条件地构建子视图,即使(重用)单元格已经具有该子视图。答案是,懒惰是你的朋友。尝试从单元格中获取子视图,并且只有在必须时才构建它...
// change all of your subview-building code to do this:
UIImageView *imageView = (UIImageView *)[cell viewWithTag:32];
if (!imageView) {
imageView = [[UIImageView alloc] init....
// same code as you had here, adding...
imageView.tag = 32;
}
// and so on for the cell's other subviews. be sure to advance the tag (33, 34, etc)
总之,cellForRowAtIndexPath有几个部分。