多次加载时 cellForRowAtIndexPath 行为异常

Posted

技术标签:

【中文标题】多次加载时 cellForRowAtIndexPath 行为异常【英文标题】:cellForRowAtIndexPath misbehaves when loading more than once 【发布时间】:2014-11-28 14:24:54 【问题描述】:

我使用以下代码创建了一个带有滑动手势的应用程序。手势应仅适用于特定行。第一次加载时它工作得很好。从第二次开始,手势功能对每一行都有效。

我的代码如下:

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

GoalDetailsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GoalDetailsCell"];

if(cell == nil)

    cell = [[GoalDetailsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"GoalDetailsCell"];


NSMutableDictionary *cellData = [self.databaseCall transactionFromDatabase:indexPath.row goalId:self.goalId andStageId:self.stageId];

cell.goalDescription.text = self.goalName;
cell.actionGoalDescription.text = self.goalName;
cell.tipsDescription.text = [cellData objectForKey:@"tipsDescription"];
UIImage *cellImage = [UIImage imageNamed:[cellData objectForKey:@"categoryImage"]];
NSLog(@"%@", [cellData objectForKey:@"cardType"]);

if([[cellData objectForKey:@"cardType"] isEqualToString:@"2"])

    UISwipeGestureRecognizer *swipeLeftGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeftMethod:)];
    swipeLeftGesture.direction = UISwipeGestureRecognizerDirectionLeft;
    [cell.cardDetails addGestureRecognizer:swipeLeftGesture];
    [cell.tryThisButton addTarget:self action:@selector(tryThisButtonPressed:) forControlEvents:UIControlEventTouchDown];

    UISwipeGestureRecognizer *swipeRightGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightMethod:)];
    swipeRightGesture.direction = UISwipeGestureRecognizerDirectionRight;
    [cell.actionCardReminder addGestureRecognizer:swipeRightGesture];
    [cell.previousButton addTarget:self action:@selector(previousButtonPressed:) forControlEvents:UIControlEventTouchDown];
    cell.tryThisButton.hidden = NO;
    [cell.tryThisButton setImage:[UIImage imageNamed:@"trythis.jpg"] forState:UIControlStateNormal];
    [cell.actionCardType setImage:[UIImage imageNamed:@"toconsider.jpg"]];
    cell.cardType.image = [UIImage imageNamed:@"toconsider.jpg"];
    cell.cardTypeImage.hidden = YES;
    cell.actionCardGoalName.text = self.goalName;
    cell.actionGoalsImage.image = cellImage;
    cell.actionCardReminder.layer.cornerRadius = 5;
    cell.datePicker.layer.borderWidth = 0.2;
    cell.datePicker.layer.borderColor = [[UIColor grayColor] CGColor];

else
    cell.tryThisButton.hidden = YES;
    cell.cardTypeImage.hidden = NO;
    cell.cardType.image = [UIImage imageNamed:@"goodtoknow.jpg"];
    cell.cardTypeImage.image = [UIImage imageNamed:@"tips.jpg"];


NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[cellData objectForKey:@"actionLink"]];
[str addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(0, [str length])];
[str addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:NSMakeRange(0, [str length])];

[cell.reminderSwitch addTarget:self action:@selector(customSwitchChanged:) forControlEvents:UIControlEventValueChanged];
[cell.datePicker addTarget:self action:@selector(datePickerButtonPressed:) forControlEvents:UIControlEventTouchDown];

cell.weburl.attributedText = str;
cell.goalName.text = self.goalName;
cell.goalsImage.image = cellImage;
cell.cardDetails.layer.cornerRadius = 5;
NSLog(@"%d", indexPath.row);

// Configure the cell...
return cell;

提前致谢。

【问题讨论】:

尝试为每种细胞类型使用两个不同的类。 你能给我一些示例程序吗 我放了一些代码作为答案(因为太长了,不能作为评论发表)。 【参考方案1】:

这是因为您使用 dequeueReusableCellWithIdentifier: 重复使用您的单元格以进行快速修复,您也许可以在 else 语句中明确删除手势识别器,例如:

else 
    cell.tryThisButton.hidden = YES;
    cell.cardTypeImage.hidden = NO;
    cell.cardType.image = [UIImage imageNamed:@"goodtoknow.jpg"];
    cell.cardTypeImage.image = [UIImage imageNamed:@"tips.jpg"];

    // To remove all swipe gestures:
    for (UIGestureRecognizer *recognizer in cell.cardDetails.gestureRecognizers) 
        [cell.cardDetails removeGestureRecognizer:recognizer];
    
    for (UIGestureRecognizer *recognizer in cell.actionCardReminder.gestureRecognizers) 
        [cell.actionCardReminder removeGestureRecognizer:recognizer];
    

不过,我确实认为有更好的方法来构建您的代码,因为当您重用单元格时,您实际上也是在将手势识别器一层一层地分层。我认为您需要想办法重用手势识别器,就像重用其他插座一样。但是为了快速解决问题,我的解决方案应该可以工作。

【讨论】:

它显示以下错误 -[UIView countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7aff2f60 @Balaji 对此感到抱歉。我在循环行的末尾省略了“.gestureRecognizers”。现在应该可以工作了。 @Balaji cardDetails 和 actionCardReminder 是什么? UIViews? @Balaji 实际拍摄。我又犯了一个错误。马上更新。 cardDetails 和 actionCardDetails 是表格单元格中的 uiViews。实际上错误已经消失,但行为与问题中的相同。【参考方案2】:

您已经标记了答案,但这里还有一些代码:

在你看来DidLoad:

[self.tableView registerClass:[GoalDetailsTableViewCell class] forCellWithReuseIdentifier:@"GoalDetailsCell"];
[self.tableView registerClass:[GoalDetailsTableViewCellWithGestures class] forCellWithReuseIdentifier:@"GoalDetailsCellWithGestures”];

在你的 cellForRowAtIndexPath 中:

if([[cellData objectForKey:@"cardType"] isEqualToString:@"2"])

GoalDetailsTableViewCellWithGestures *cell = [tableView dequeueReusableCellWithIdentifier:@"GoalDetailsCellWithGestures"];
// configure this type of cell (text, gestures, etc)
return cell;

else

GoalDetailsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GoalDetailsTableViewCell"];
// configure this type of cell (text, etc)
return cell;

【讨论】:

但我没有任何标识符为“GoalDetailsCellWithGestures”的单元格 这就是想法:创建两种不同类型的单元格(一种有手势,另一种没有手势)并相应地配置它们。

以上是关于多次加载时 cellForRowAtIndexPath 行为异常的主要内容,如果未能解决你的问题,请参考以下文章

多次加载时 cellForRowAtIndexPath 行为异常

Swift:多次加载表格时崩溃

重新加载 Fragment 时多次调用 Fragment onCreate

在运行时多次加载 Roslyn 编译的 DLL

如何防止部分视图中的脚本多次加载并在同一页面中多次使用部分时导致错误

vue路由多个子路由页面加载多次