使用 UITableViewController cellForRowAtIndexPath 获取重复的单元格 [英] Getting duplicate cells with UITableViewController cellForRowAtIndexPath

查看:25
本文介绍了使用 UITableViewController cellForRowAtIndexPath 获取重复的单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 UITableViewController 创建一个表视图.

I am trying to create a Table View using a UITableViewController.

'cellForRowAtIndexPath' 似乎工作不正常——我从 Parse 预先加载了照片和评论并将它们放在一个数组中,并且想要填充屏幕宽度的图片,所以我正在做一些手动操作对它们进行计算以调整大小.

The 'cellForRowAtIndexPath' doesn't seem to be working right-- I have pre-loaded photos and comments from Parse and put them in an array, and want pictures that fill up the screen width, so I am doing some manual calculations on them to resize.

我正在做一些不寻常的事情以使表格视图看起来正确,但现在数据重复了.

I am doing some unusual things to get the Table View to look right, but now the data is duplicated.

我知道这里有一些我没有得到的东西,但我不确定它是什么......也许我需要做一些其他事情来绑定数据,或者使用prepareForReuse"方法做一些事情?

I know there is something here that I'm not getting, but I'm not really sure what it is... maybe I need to do something else to bind the data, or do something with the "prepareForReuse" method?

我已经包含了来自 UITableViewController 子类和我编写的 UITableCell 子类的代码.

I have included code from the UITableViewController subclass and the UITableCell subclass I wrote.

import UIKit

class YouTableViewCell: UITableViewCell {

var recipeId:String = ""
var recipeName:String = ""
var imageHeight:CGFloat = 0
var labelHeight:CGFloat = 0

// DO I NEED THIS?
override func prepareForReuse() {
    self.textLabel!.text = recipeId //Put your label name
    self.imageView!.image = nil

}

override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
 }

 }

 class YouTableViewController: BaseTableViewController { // UITableViewController {

var labelCreated = [Bool]()
var imageCreated = [Bool]()

var cellArray = [Int:YouTableViewCell]()


override func viewDidLoad() {
    super.viewDidLoad()

    self.tableView.delegate = self
    self.tableView.dataSource = self

    self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())

    if !isYouDataLoaded {
        _ = DataController.getYouPageData()
    }


    // initialize height arrays
    for _ in 0..<youFeed.count {
        labelCreated.append(false)
        imageCreated.append(false)
    }


    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    self.navigationController?.setToolbarHidden(false, animated: false)
}

 // ... skipping down


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // return feedArray.count
    return youFeed.count
}



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    print("cellForRowAtIndexPath : \(indexPath.row)")

    // Get reference to cell
    cellArray[indexPath.row] = (tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! YouTableViewCell)
    let thisCell:YouTableViewCell = cellArray[indexPath.row]!


    // TEMP -- Border
    thisCell.layer.borderWidth = 2.0
    thisCell.layer.borderColor = UIColor.blackColor().CGColor

    let meal = youFeed[indexPath.row].recipe

    // If the image exists
    if let foodImage:UIImage = meal.imageView.image! as UIImage {
        var nameLabel:UILabel = UILabel()
        var fitImageView:UIImageView?
        if imageCreated[indexPath.row] == false {
            print("For IMAGE #\(indexPath.row)")
            fitImageView = LayoutHelper.fitImageInCell(foodImage, cell: thisCell, name: meal.recipeName)
            thisCell.contentView.addSubview(fitImageView!)

            thisCell.imageHeight = fitImageView!.frame.height
            fitImageView!.frame.origin.y = 0
            print("img height : \(fitImageView!.image!.size.height)")
            imageCreated[indexPath.row] = true
        }
        if labelCreated[indexPath.row] == false {
            // Create Label
            var captionString = ""
            if let mealNameText:String = meal.recipeName as String {
                captionString += mealNameText
            }

            if let postText:String = meal.desc as String {
                captionString += "\n" + postText
            } else {
                print("Meal Desc is null")
            }
            if let numForks:Int = meal.forks as Int {
                captionString += "\n" + String(numForks) + " Forks"
            }
            if (fitImageView != nil) {
                nameLabel = LayoutHelper.fitLabelBelowImageView(captionString, imageView: fitImageView!, cell: thisCell, yOffset: 0)
                thisCell.addSubview(nameLabel)
                thisCell.labelHeight = nameLabel.frame.height
            }
        }
    } 
    return thisCell
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let thisCell = cellArray[indexPath.row]

    var thisHt:CGFloat = 0
    if thisCell != nil {
        thisHt = thisCell!.labelHeight + thisCell!.imageHeight
    }
    return thisHt
}
}

推荐答案

当你重复使用单元格时(这是一件好事!)你必须每次都重新初始化整个单元格 cellForRowAtIndexPath 被调用.这是因为当您拨打此电话时,可能:

When you re-use cells (which is a good thing to do!) you must re-initialize the entire cell every time cellForRowAtIndexPath is called. This is because it is possible that when you make this call:

tableView.dequeueReusableCellWithIdentifier

它可能会返回一个您已经初始化的单元格.例如,假设我在屏幕上有 4 行可见:

it could be returning a cell that you have already initialized. For example, let's say I have 4 rows visible on the screen:

Row 1 - Cell A [Image 1]
Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]

现在,假设我向下滚动,第 1 行不再出现在屏幕上,但第 5 行现在出现了.您收到的第 5 行单元格可能与第 1 行的单元格完全相同.因此,在调用 tableView.dequeueReusableCellWithIdentifier 后,第 5 行看起来像这样:

Now, let's say I scroll down and Row 1 is no longer on the screen, but Row 5 has now appeared. It is possible that the cell you receive for Row 5 is the same exact cell that was at Row 1. So, immediately after the call to tableView.dequeueReusableCellWithIdentifier Row 5 looks like this:

Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]
Row 5 - Cell A [Image 1] <--

您需要更新单元格 A 以指向图像 5.这可能在您的代码中工作正常,您会得到:

You need to update Cell A to point to Image 5. That may work fine in your code and you get this:

Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]
Row 5 - Cell A [Image 5] <--

现在,假设您向上滚动并再次为第 1 行分配单元格 A:

Now, let's say you scroll back up and Row 1 is assigned Cell A again:

Row 1 - Cell A [Image 5] <--
Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]

由于您存储的数组用于跟踪已初始化的行(imageCreatedlabelCreated),因此单元格不会更新为指向图像 1:

Since you are storing arrays that keep track of which rows have been initialized (imageCreated, labelCreated) the cell won't get updated to point to Image 1:

// THIS WILL BE TRUE, SO IT WILL NOT EXECUTE
if imageCreated[indexPath.row] == false

这意味着摆脱您的 imageCreatedlabelCreated 数组,并在每次调用 cellForRowAtIndexPath 时执行代码来初始化您的单元格.

This means get rid of your imageCreated and labelCreated arrays and perform the code to initialize your cells every time cellForRowAtIndexPath is called.

另外,我建议去掉 cellArray 并且不存储对单元格的引用(出于我上面提到的相同原因).您可以缓存单元高度,这应该没问题,因为它们与可重用单元无关.你可以这样做:

Also, I would recommend getting rid of the cellArray and not storing references to cells (for the same reasons I mentioned above). You can cache cell heights and that should be fine because those are not tied to re-usable cells. You could do something like this:

var cellHeightArray = [Int:CGFloat]()

由于您在 cellForRowAtIndexPath 中进行计算,因此将高度设置在底部:

Since you are doing calculations in cellForRowAtIndexPath set the height at the bottom:

cellHeightArray[indexPath.row] = thisCell!.labelHeight + thisCell!.imageHeight;

然后从heightForRowAtIndexPath中的数组中设置:

Then set it from the array in heightForRowAtIndexPath:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let thisCellHeight = cellHeightArray[indexPath.row]

    var thisHt:CGFloat = 0
    if thisCellHeight != nil {
        thisHt = thisCellHeight
    }
    return thisHt
}

默认情况下,但是我相信 heightForRowAtIndexPathcellForRowAtIndexPath 之前被调用.在这种情况下,您的某些单元格的高度将为 0,直到您重新加载 tableview.查看此帖子了解更多信息:

By default, however I believe heightForRowAtIndexPath is called before cellForRowAtIndexPath. In that case some of your cells will have a height of 0 until you reload the tableview. Look at this post for more information:

为什么 heightForRowAtIndexPath: 在 cellForRowAtIndexPath: 之前?

这篇关于使用 UITableViewController cellForRowAtIndexPath 获取重复的单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆