ios 何时使用 dequeueReusableCellWithIdentifier 与 dequeueReusableCellWithIdentifier : forIndexPath

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25826383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:25:52  来源:igfitidea点击:

When to use dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier : forIndexPath

iosobjective-cswift

提问by Jaja Harris

There are two overloads for dequeueReusableCellWithIdentifier and I'm trying to determine when should I use one vs the other?

dequeueReusableCellWithIdentifier 有两个重载,我正在尝试确定何时应该使用一个还是另一个?

The apple docs regarding the forIndexPath function states, "This method uses the index path to perform additional configuration based on the cell's position in the table view."

关于 forIndexPath 函数的苹果文档指出,“此方法使用索引路径根据表格视图中单元格的位置执行附加配置。”

I'm not sure how to interpret that though?

我不知道如何解释?

回答by rob mayoff

The most important difference is that the forIndexPath:version asserts (crashes) if you didn't register a class or nib for the identifier. The older (non-forIndexPath:) version returns nilin that case.

最重要的区别是,forIndexPath:如果您没有为标识符注册类或笔尖,则版本会断言(崩溃)。在这种情况下,旧的(非forIndexPath:)版本返回nil

You register a class for an identifier by sending registerClass:forCellReuseIdentifier:to the table view. You register a nib for an identifier by sending registerNib:forCellReuseIdentifier:to the table view.

您可以通过发送registerClass:forCellReuseIdentifier:到表视图来为标识符注册一个类。您可以通过发送registerNib:forCellReuseIdentifier:到表视图来为标识符注册一个笔尖。

If you create your table view and your cell prototypes in a storyboard, the storyboard loader takes care of registering the cell prototypes that you defined in the storyboard.

如果您在故事板中创建表格视图和单元格原型,故事板加载器会负责注册您在故事板中定义的单元格原型。

Session 200 - What's New in Cocoa Touch from WWDC 2012discusses the (then-new) forIndexPath:version starting around 8m30s. It says that “you will always get an initialized cell” (without mentioning that it will crash if you didn't register a class or nib).

第 200 节 - WWDC 2012 的 Cocoa Touch 的新功能讨论了forIndexPath:大约 8 分 30 秒开始的(当时的新)版本。它说“你总是会得到一个初始化的单元格”(没有提到如果你没有注册一个类或笔尖它会崩溃)。

The video also says that “it will be the right size for that index path”. Presumably this means that it will set the cell's size before returning it, by looking at the table view's own width and calling your delegate's tableView:heightForRowAtIndexPath:method (if defined). This is why it needs the index path.

该视频还说“它将是该索引路径的正确大小”。大概这意味着它将在返回之前设置单元格的大小,通过查看表格视图自己的宽度并调用您的委托tableView:heightForRowAtIndexPath:方法(如果已定义)。 这就是它需要索引路径的原因。

回答by GoodSp33d

dequeueReusableCellWithIdentifier:forIndexPath:will alwaysreturn a cell. It either re uses existing cells or creates a new one and returns if there are no cells.

dequeueReusableCellWithIdentifier:forIndexPath:始终返回一个单元格。它要么重新使用现有单元格,要么创建一个新单元格并在没有单元格时返回。

While, the traditional dequeueReusableCellWithIdentifier:will return a cell if it exists i.e if there is a cell which can be reused it returns that else it returns nil. So you would have to write a condition to check for nilvalue as well.

而传统的dequeueReusableCellWithIdentifier:将返回一个单元格,如果它存在,即如果有一个可以重用的单元格,它返回否则它返回 nil。因此,您还必须编写一个条件来检查nil值。

To answer your question use dequeueReusableCellWithIdentifier:when you want to support iOS 5 and lower versions since dequeueReusableCellWithIdentifier:forIndexPathis only available on iOS 6+

dequeueReusableCellWithIdentifier:当您想支持 iOS 5 及更低版本时,请使用回答您的问题,因为dequeueReusableCellWithIdentifier:forIndexPath仅适用于 iOS 6+

Reference : https://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:forIndexPath:

参考:https://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:forIndexPath

回答by rdelmar

I have never understood why Apple created the newer method, dequeueReusableCellWithIdentifier:forIndexPath:. Their documentation on them is not complete, and is somewhat misleading. The only difference I've been able to discern between the two methods, is that that older method can return nil, if it doesn't find a cell with the identifier passed in, while the newer method crashes, if it can't return a cell. Both methods are guaranteed to return a cell, if you have set the identifier correctly, and make the cell in a storyboard. Both methods are also guaranteed to return a cell if you register a class or xib, and make your cell in code or a xib file.

我一直不明白为什么 Apple 创建了较新的方法 dequeueReusableCellWithIdentifier:forIndexPath:。他们的文档不完整,有些误导。我能够辨别这两种方法的唯一区别是,旧方法可以返回 nil,如果它没有找到带有传入标识符的单元格,而新方法则崩溃,如果它不能返回一个细胞。如果您正确设置了标识符,并在故事板中制作单元格,这两种方法都保证返回一个单元格。如果您注册一个类或 xib,并在代码或 xib 文件中制作您的单元格,则这两种方法也都保证返回一个单元格。

回答by SLN

For short:

简而言之:

dequeueReusableCell(withIdentifier, for)only works with prototype cells. If you tried to use it when the prototype cell is absence, it would crash the app.

dequeueReusableCell(withIdentifier, for)仅适用于原型单元格。如果您在原型单元不存在时尝试使用它,它会使应用程序崩溃。

Hollemans M.2016, Chapter 2 Checklist, IOS Apprentice(5th Edition). pp: 156.

Hollemans M.2016,第 2 章清单,IOS Apprentice(第 5 版)。pp:156。

回答by hhamm

I would recommend to use both if you are using dynamic generated content. Otherwise your app might crash unexpectedly. You could implement your own function to retrieve an optional reusable cell. If it is nilyou should return an empty cell that is not visible:

如果您使用动态生成的内容,我建议您同时使用两者。否则您的应用可能会意外崩溃。您可以实现自己的函数来检索可选的可重用单元格。如果是,nil您应该返回一个不可见的空单元格:

Swift 3

斯威夫特 3

// Extensions to UITableView
extension UITableView
{
    // returns nil, if identifier does not exist. 
    // Otherwise it returns a configured cell for the given index path
    open func tryDequeueReusableCell (
        withIdentifier identifier: String, 
        for indexPath: IndexPath) -> UITableViewCell?
    {
        let cell = self.dequeueReusableCell(withIdentifier: identifier)
        if cell != nil {
            return self.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        }  
        return nil
    }
}

And the extension to return an empty cell:

以及返回空单元格的扩展名:

// Extension to UITableViewCell
extension UITableViewCell
{
    // Generates an empty table cell that is not visible
    class func empty() -> UITableViewCell
    {
        let emptyCell = UITableViewCell(frame:CGRect(x:0, y:0, width:0, height:0))
        emptyCell.backgroundColor = UIColor.clear
        return emptyCell
    }
}

A complete example of how to use it:

如何使用它的完整示例:

import Foundation
import UIKit

// A protocol is used to identify if we can configure
// a cell with CellData
protocol ConfigureAbleWithCellData
{
    func configure(_ data: CellData)
}

class MyCustomTableViewCell :
    UITableViewCell,
    ConfigureAbleWithCellData
{
    @IBOutlet weak var title:UILabel! = nil
    func configure(_ data: CellData)
    {
        self.title.text = data.title
    }
}

// This actually holds the data for one cell
struct CellData
{
    var title:String = ""
    var reusableId:String = ""
}

class CosmoConverterUnitTableViewController:
    UIViewController,
    UITableViewDelegate,
    UITableViewDataSource
{
    // Storage
    var data = Array<Array<CellData>>()

    func loadData()
    {
        var section1:[CellData] = []
        var section2:[CellData] = []

        section1.append(CellData(title:"Foo", reusableId:"cellType1"))
        section2.append(CellData(title:"Bar", reusableId:"cellType2"))

        data.append(section1)
        data.append(section2)
    }

    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int) -> Int
    {
        return data[section].count
    }

    public func numberOfSections(in tableView: UITableView) -> Int
    {
        return data.count
    }

    func tableView(
        _ tableView: UITableView,
        cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        guard
            indexPath.row < data[indexPath.section].count
            else
        {
            fatalError("this can't be")
        }

        let cellData = data[indexPath.section][indexPath.row]

        if let cell = tableView.tryDequeueReusableCell(
            withIdentifier: cellData.reusableId,
            for: indexPath)
        {
            if let configurableCell = cell as? ConfigureAbleWithCellData
            {
                configurableCell.configure(cellData)
            }
            else
            {
                // cell is not of type ConfigureAbleWithCellData
                // so we cant configure it.
            }
            return cell
        }
        // id does not exist
        return UITableViewCell.empty()
    }
}