tableView.dequeueReusableCellWithIdentifier 与 tableView.cellForRowAtIndexPath 的区别

4

我的Xcode是7.1,模拟器是iPhone6。
通常我使用dequeueResuableCellWithIdentifier,但这一次我遇到了问题。

我的问题是:
在选择新行之后,它没有清除我的orangeColor(),但打印行deselecting indexPath是正确的。

我的解决方案是:
我改为从
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyCell;

let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyCell;
然后就解决了我的问题。背景颜色是clearColor()

以下是我的文件:
MyCell.swift :

import UIKit

class MyCell: UITableViewCell {
    @IBOutlet weak var myLabel : UILabel!
    @IBOutlet weak var myWebView : UIWebView!;
    //@IBOutlet weak var myView : UIView!;
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code.
    }

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

        // Configure the view for the selected state
    }

}

ViewController.swift :

import UIKit

class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableViewObject: UITableView!

    var fruits = ["Apple", "Banana","Cherry", "Durian", "ElderBerry"];
    var selectedIndexPath : NSIndexPath?;
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableViewObject.delegate = self;
        self.tableViewObject.dataSource = self;
        // Do any additional setup after loading the view, typically from a nib.
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return fruits.count;
    }
    func loadCellContent(acell : UITableViewCell, indexPath : NSIndexPath, color: UIColor){
        let cell = acell as! MyCell;
        cell.myLabel.text = String(UnicodeScalar(65 + indexPath.row));
        cell.myWebView.loadHTMLString(fruits[indexPath.row], baseURL: nil);
        cell.myWebView.scrollView.bounces = false;
        cell.myWebView.scrollView.scrollEnabled = false;
        cell.myWebView.userInteractionEnabled = false;
        cell.backgroundColor = color;
        cell.myLabel.backgroundColor = color;
        cell.myWebView.backgroundColor = color;
    }
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyCell;
        self.loadCellContent(cell, indexPath: indexPath, color: UIColor.clearColor());
        return cell;
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int{
        return 1;
    }
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        //let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyCell;
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyCell;
        self.loadCellContent(cell, indexPath: indexPath, color : UIColor.orangeColor());
    }
    func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
        //let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyCell;
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyCell;
        self.loadCellContent(cell, indexPath: indexPath,color: UIColor.clearColor());
        print("Hellos", indexPath.row);

    }
}

我的问题是:
1、dequeueReusableCellWithIdentifer方法和cellForRowAtIndexPath方法有什么主要区别?
2、什么时候使用第一个方法,什么时候使用第二个方法,我怎样知道呢? 这一次我从一个教程试着去做到另一个。

更新:
我有物理学背景和一点计算机科学知识,请不要因为我幼稚的问题等而生气。


1
可能是重复的问题:iPhone - dequeueReusableCellWithIdentifier usage - Anbu.Karthik
dequeueReusableCellWithIdentifer 应仅在 cellForRowAtIndexPath 的实现中使用。 - rmaddy
@Anbu.Karthik感谢你的搜索。我现在对 dequeueReusableCellWithIndentifier() 有更深入的理解了。我的理解是dequeue会重用内存,但是cellForRowAtIndexPath不会重用内存。我是正确的吗?我仍然不清楚为什么第二个会起作用,而第一个不会。 - joe
@rmaddy抱歉我不理解。您能给我举个例子来解释一下吗? - joe
@rmaddy。我明白了!谢谢 :) - joe
显示剩余2条评论
2个回答

3
试图不在内存中一直保存所有的单元格对象实例:
  • 'dequeueReusableCellWithIdentifer'会回收或创建一个单元格,并应该在'cellForRow...'中调用。这个方法始终返回一个单元格实例,无论是新建的还是以前不再可见的。然后你需要为显示准备这个单元格。

  • 'cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell? //如果单元格不可见或索引路径超出范围,则此方法返回nil',它只是给你访问这些单元格的权限,而不会创建单元格。我认为应该尽量避免使用此方法,以防止意外泄漏和其他对tableView的干扰。

关于您的“setSelected”问题:

  • 在单元格类中实现准备重用(将所有值设置为默认值)是一个好主意。
  • 在'didSelectRow'中你不需要重新加载单元格内容(此时用户只是点击了它,因此已经加载过)。
  • 你可能需要在单元格的'setSelected'之间切换橙色/清除颜色。

你的评论:“dequeueReusableCellWithIdentifer” 返回的是一个单元格实例,这种说法并不准确。实际上,在许多情况下它会返回“nil”。 - rmaddy
@rmaddy - 对你的观察进行了微小的改进:如果你使用dequeueReusableCellWithIdentifier:indexPath:(这是OP在他的代码示例中使用的方法,也是Andrei可能指的方法...他应该澄清一下),它总是返回一个单元格实例。另一方面,如果你指的是旧的dequeueReusableCellWithIdentifier:,那么如果没有与该标识符关联的类/nib/原型,并且重用队列中没有单元格,则可以返回nil - Rob
1
@Rob 很好的澄清。我应该更清楚地指出我是在引用 dequeueReusableCellWithIdentifier: 方法,而不是那个还带有索引路径的方法。 - rmaddy

2
这两种方法有不同的用途。
1. dequeueReusableCellWithIdentifier:indexPath: 方法在必要时实例化一个新的单元格,但如果之前已经滚动出屏幕的单元格可用,则会重用它。只能从 tableView:cellForRowAtIndexPath: 中调用此方法。
2. cellForRowAtIndexPath: 方法(不要与类似命名的 tableView:cellForRowAtIndexPath: 方法混淆)不会实例化新的单元格,而是仅用于获取对当前可见的先前实例化的单元格的引用。如果单元格不可见(例如,已滚动出屏幕),则返回nil。在 tableView:didSelectRowAtIndexPath:tableView:didDeselectRowAtIndexPath: 等方法中使用此方法,因为您只是尝试获取对现有单元格的引用,而不是实例化新单元格。
在您的代码示例中,请注意您不仅从 tableView:cellForRowAtIndexPath: 调用了 loadCellContent,还从 tableView:didSelectRowAtIndexPath:tableView:didDeselectRowAtIndexPath: 中调用了它。建议将单元格的初始配置(例如,loadCellContent,您仅从 tableView:cellForRowAtIndexPath: 调用)与背景颜色的调整分开(在 didSelect...didDeselect... 中进行)。这两个方法通常不会重新配置整个单元格,而只是更新背景颜色(或执行适当的修饰以显示选择)。
此外,您需要确保在配置背景颜色时,tableView:cellForRowAtIndexPath: 检查单元格是否被选中。用户可能会选择一个单元格,将其滚动出屏幕,然后再将其滚动回屏幕,此时 tableView:cellForRowAtIndexPath: 必须检查单元格是否被选中,以设置背景颜色。
例如:
// MARK: Cell configuration

func loadContentForCell(cell: UITableViewCell, indexPath: NSIndexPath) {
    // do whatever you need here; I'm just going to set the `textLabel`
    cell.textLabel?.text = "Row \(indexPath.row)"
}

func updateBackgroundColorForCell(cell: UITableViewCell?) {
    cell?.contentView.backgroundColor = cell?.selected == true ? UIColor.redColor() : UIColor.whiteColor()
}

// MARK: UITableViewDataSource

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 100
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    
    loadContentForCell(cell, indexPath: indexPath)
    updateBackgroundColorForCell(cell)
    
    return cell
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let cell = tableView.cellForRowAtIndexPath(indexPath)
    updateBackgroundColorForCell(cell)
}

override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
    let cell = tableView.cellForRowAtIndexPath(indexPath)
    updateBackgroundColorForCell(cell)
}

非常感谢。从现在开始,我将遵循你的示例格式,我清楚了如何实现这些函数:] - joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接