【问题标题】:How to Set UITableViewCellStyleSubtitle and dequeueReusableCell in Swift?如何在 Swift 中设置 UITableViewCellStyleSubtitle 和 dequeueReusableCell?
【发布时间】:2014-07-26 13:41:01
【问题描述】:

我想要一个带有subtitle 样式单元格的UITableView,并使用dequeueReusableCellWithIdentifier

我原来的 Objective-C 代码是:

static NSString *reuseIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(!cell)
{
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}

在 SO 上搜索了几个 UITableView 问题后,我想像这样用 Swift 编写它:

tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "Cell")

let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

但这并不能让我说我想要subtitle 风格。所以我尝试了这个:

var cell :UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")

这给了我一个subtitle 单元格,但它没有让我dequeueReusableCellWithIdentifier

我研究了更多内容并查看了 this video tutorial,但他创建了一个单独的 subclassUITableViewCell,我认为这是不必要的,因为我之前在 Obj-C 中完成了同样的效果。

有什么想法吗?谢谢。

【问题讨论】:

  • 你能澄清一下“它不允许我dequeueReusableCellWithIdentifier”是什么意思吗?我不清楚。
  • @68cherries 抱歉,我不是指“功能”,不知道该怎么称呼它。方法?基本上,我希望我的单元格出列,正如我在 SO 上所读到的那样,如果您使用 dequeueReusableCellWithIdentifier,它会重用单元格,因此效率更高。
  • 为什么不用和以前一样的代码呢?如果是 nil 则将一个单元格出列使用 swift constructor 初始化一个新单元格。
  • 由于单元格不再是nil,这里的答案都是过时的除了Meilbn's answer

标签: ios uitableview swift


【解决方案1】:

我请你看看 Github 上的这个小 UITableView-Example:https://github.com/YANGReal/UITableView-Swift

他们的行为如下:

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
   let cell = tableView .dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
   cell.textLabel.text = String(format: "%i", indexPath.row+1)
   // set any other property of your cell here
   return cell
}

【讨论】:

  • 这是视频教程中的人(原始问题中的链接)所做的,但我想使用单元格样式的字幕。为此,他创建了一个单独的 UITableViewCell 子类,我认为这是不必要的。我希望它是,至少!
【解决方案2】:

请记住,UITableView 在函数中被定义为可选项,这意味着您的初始单元格声明需要检查属性中的可选项。此外,返回的排队单元也是可选的,因此请确保将可选转换为UITableViewCell。之后,我们可以强制展开,因为我们知道我们有一个单元格。

var cell:UITableViewCell? = 
tableView?.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell
if (cell == nil)
{
   cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, 
                reuseIdentifier: reuseIdentifier)
}
// At this point, we definitely have a cell -- either dequeued or newly created,
// so let's force unwrap the optional into a UITableViewCell
cell!.detailTextLabel.text = "some text"

return cell

【讨论】:

  • NP。语法对我们所有人来说仍然有点棘手,但越使用它就会越自然。
  • @RafaelBarros 我不明白这与这个问题有什么关系,因为那个问题是关于自定义单元格的。
  • dequeueReusableCell 从 iOS 4 开始总是返回一个单元格。
  • 支票不应该是if cell == nil { // instantiate a new one } 吗?
  • @LShi 不完全是。 dequeueReusableCell(withIdentifier:forIndexPath:) 确实返回了一个非可选单元格,但 dequeueReusableCell(withIdentifier:) 仍然返回一个可选单元格。
【解决方案3】:

按照 Michael G. Emmons 的建议完美,但在 Xcode 6.1 中使用

if !cell { .....

我收到此错误:

可选类型'@|value UITableViewCell?'不能用作布尔值; 改为测试 '!= nil'

可接受的语法是:

if cell == nil { ...

【讨论】:

    【解决方案4】:

    您可以使用与 memmons 中的语法稍有不同的语法来防止强制展开:

    let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell ?? UITableViewCell(style: .Subtitle, 
                reuseIdentifier: reuseIdentifier)
    
    cell.detailTextLabel?.text = "some text"
    
    return cell
    

    这是使用 XCode 6.1 7、Swift 1.2 2.0 语法,其中 UITableView 不再是可选的。

    【讨论】:

    • Swift 2 : cell.detailTextLabel!.text = "some text" return cell
    【解决方案5】:
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath:
     NSIndexPath) -> UITableViewCell {  
         var CellIdentifier:String = "Cell"  
         var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as? UITableViewCell  
         if cell == nil {  
            cell = UITableViewCell(style:UITableViewCellStyle(rawValue:3)!,reuseIdentifier:CellIdentifier)   
          }
        return cell!
    }
    

    【讨论】:

      【解决方案6】:
      func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
          let reuseIdentifier = "cell"
          var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as UITableViewCell?
          if (cell == nil) {
              cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier)
          }
          cell!.textLabel?.text = self.items[indexPath.row]
          cell!.detailTextLabel?.text = self.items[indexPath.row]
          return cell!
      }
      

      【讨论】:

      • 虽然代码可能很好地回答了这个问题,但考虑解释它以获得更全面的答案
      • 如果我没记错的话,你应该把 if 条件上的 "!=" 替换为 "=="
      【解决方案7】:

      通过清理 Swift 2 风格来构建 memmons 的答案...

      let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) ?? UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier)
      
      cell.detailTextLabel?.text = "some text"
      
      return cell
      

      斯威夫特 3:

      let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) ?? UITableViewCell(style: .subtitle, reuseIdentifier: cellIdentifier)
      
      cell.detailTextLabel?.text = ""
      
      return cell
      

      【讨论】:

        【解决方案8】:

        与其他答案基本相同,但我通过使用计算变量来处理讨厌的选项(您不能在 Swift 中从 -tableView:cellForRow:atIndexPath: 返回 nil):

        斯威夫特 3

        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
            let cell: UITableViewCell = {
                guard let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell") else {
                    // Never fails:
                    return UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: "UITableViewCell")
                }
                return cell
            }()
        
            // (cell is non-optional; no need to use ?. or !)
        
            // Configure your cell:
            cell.textLabel?.text       = "Key"
            cell.detailTextLabel?.text = "Value"
        
            return cell
        }
        

        编辑:

        实际上,最好使用tableView.dequeueReusableCell(withIdentifier:for:) 将单元格出列。

        如果没有可重用的单元格(正是我的代码在上面明确执行的操作),该函数的后一种变体会自动实例化一个新单元格,因此从不返回nil

        【讨论】:

        • 与其用立即调用的闭包做有趣的事情,不如使用 nil 合并运算符并说 tableView.dequeueReusableCell(...) ?? UITableViewCell(...)
        【解决方案9】:
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
        {
        
            var cell:UITableViewCell? =
                tableView.dequeueReusableCell(withIdentifier: "cell")
            if (cell != nil)
            {
                cell = UITableViewCell(style: UITableViewCellStyle.subtitle,
                                       reuseIdentifier: "cell")
            }
            cell!.textLabel?.text = "ABC"
            cell!.detailTextLabel?.text = "XYZ"
        
            return cell!
        
          }
        

        【讨论】:

          【解决方案10】:

          由于tableView.dequeueReusableCell(withIdentifier:, for:) 返回一个非零单元格,if cell == nil 检查始终为假。 但是我找到了一个解决方案,使默认样式单元格成为您想要的样式(值1,值2或字幕),因为默认样式单元格的detailTextLabel为nil,所以检查detailTextLabel是否为nil,然后创建新的样式单元格,并将其交给出列单元格,例如:

          斯威夫特 3:

          var cell = tableView.dequeueReusableCell(withIdentifier: yourCellReuseIdentifier, for: indexPath)
          
          if cell.detailTextLabel == nil {
              cell = UITableViewCell(style: .value1, reuseIdentifier: repeatCellReuseIdentifier)
          }
          
          cell.textLabel?.text = "Title"
          cell.detailTextLabel?.text = "Detail"
          
          return cell
          

          这对我有用。

          希望对你有所帮助。

          【讨论】:

          • 太棒了!此外,要使用上述保护语句,请使用:guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell"), cell.detailTextLabel != nil else {
          • @HelloimDarius 感谢您的补充。
          • 该代码效率低下,因为第 4 行创建了一个额外的单元格,如果repeatCellReuseIdentifier != yourCellReuseIdentifier,则该额外的单元格将永远不会被重用。
          • @ma11hew28 正如我所说:tableView.dequeueReusableCell(withIdentifier:, for:) 返回一个非零单元格,如果你想避免创建额外的单元格,你可以制作自己的字幕样式单元格,我的方式只是一种懒惰的方式。 :)
          【解决方案11】:

          如果您没有使用自己的自定义单元格。只需通过代码注册 UITableViewCell 即可。然后你可以选择代码。

          否则选择情节提要,选择您的 TableViewCell -> Goto Attribute Inspector 并选择所需的样式,如下所示。

          【讨论】:

            【解决方案12】:

            如果您想避免可选性,您可以创建一个 UITableViewCell 的子类,如下所示:

            class SubtitleTableViewCell: UITableViewCell {
            
                override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
                    super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
                }
            
                required init?(coder aDecoder: NSCoder) {
                    fatalError("init(coder:) has not been implemented")
                }
            }
            

            然后使用注册它:

            override func viewDidLoad() {
                super.viewDidLoad()
                self.tableView.register(SubtitleTableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
            }
            

            这使您的单元格自定义代码非常好:

            override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
                let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
            
                cell.textLabel?.text = "foo"
                cell.detailTextLabel?.text = "bar"
            
                return cell
            }
            

            【讨论】:

            • 这就是我要找的。​​span>
            • 非常感谢。在创建自定义单元格 tableView 的过程中,我试图弄清楚 .subtitle 样式的设置位置。
            • 在这种情况下我们必须继承 UITableViewCell 吗?我们没有其他方法可以注册带有字幕的单元格吗?
            • 对于通用的UITableView 实现,据我所知,这是最好的方法。
            【解决方案13】:

            确保您没有将任何单元格注册到 tableview。

            如果你这样做了,dequeueReusableCellWithIdentifier 将始终提供一个非可选单元格,因此 UITableViewCellStyle.Subtitle 永远不会启动。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-05-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-02-18
              • 2020-04-25
              相关资源
              最近更新 更多