2014-10-05 105 views
0

我创建了一个UITableView,其中包含显示Users的单元格。在此方法-tableView:cellForRowAtIndexPath:内添加每个单元格。并且每个单元格都有与特定用户链接的内容,如UIImageViewUILabelUITableView滚动时的奇怪行为

只要没有超过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

请问您可以发布代码吗?特别是'tableView:cellForRowAtIndexPath:' – nburk 2014-10-05 19:20:20

+0

对于不了解单元重用的人来说,这是一个非常普遍的问题。由于滚动时单元格会被重用,因此您需要设置cellForRowAtIndexPath中的所有内容。 – rdelmar 2014-10-05 19:26:39

+0

我更新了代码,只是忽略Parse.com的东西,这是不相关的,我认为 – Peter 2014-10-05 19:28:39

回答

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 
    } 
} 
+0

我试过这个,现在当我滚动UITableView时,它在原始内容上添加了新的内容。所以单元格包含双层,高音等等内容层。 – Peter 2014-10-05 19:41:39

+0

我坚信这是因为这种比较:'tableview == commentViewTableView'。 Wny你在做这个吗?你应该知道Objective-C中的对象相等性是通过以下方式测试的:[tableView isEqual:commentViewTableView] – nburk 2014-10-05 19:44:51

+0

在这里进行比较似乎很奇怪......你真的需要这样吗?也许你应该考虑改变一些你的设置,如果这是这种情况,因为这是相当通常的模式... – nburk 2014-10-05 19:46:28

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几节。

  • 离队
  • 懒建立子视图与如上
  • 细胞:访问您的模型和乐观的init从模型子视图
  • 如果模型的部分缺失,做一个非同步呼叫,更新模型, 和完成时重新加载单元格
1

我通过更改单元格标识符是唯一的解决了我的问题。我不知道这是否是实现这一目标的方式,或者如果这是好的做法,但是当我做到了时,它就解决了我的问题。所以,如果有一些反馈意见,以便知道这是否会导致我可能错过的任何其他问题,那就太好了。

NSString *identifier = [NSString stringWithFormat:@"Cell%li", indexPath.row]; 
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:identifier]; 

if (cell == nil) { 
    //My code.. 
} 
+0

谢谢你解决了我的问题:) – blganesh101 2015-03-11 10:50:23