Swift - 型铸造

时间:2016-04-22 18:16:17

标签: ios swift uitableview casting

我正在使用自定义单元格构建自定义UITableView。 每个自定义单元格都是FormItemTableViewCell

的子类

我正在尝试填充cellForRowAtIndexPath

中的单元格数据
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        var cell = FormItemTableViewCell();

        if(indexPath.row == 1){
            cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
        } else {
            cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
        }



        cell.questionLabel.text = "What is the meaning of life?";

        return cell
    }

如何访问子类中的元素?

例如:TwoOptionTableViewCell有一个segControlOneTextFieldTableViewCell有一个answerTextField

4 个答案:

答案 0 :(得分:3)

您可以使用以下两种方法之一:

1)最好的方法:

    if(indexPath.row == 1) {
        let cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
        // the type of cell is TwoOptionTableViewCell. Configure it here.
        return cell
    } else {
        let cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
        // the type of cell is TwoOptionTableViewCell. Configure it here.
        return cell
    }

2)如果你只宣称cell一次,作为一个超类,那么你必须像这样向下转发它。

var cell: FormItemTableViewCell

cell = ... // dequeue and assign the cell like you do in your code.

if let twoOptionCell = cell as? TwoOptionTableViewCell
{
     // configure twoOptionCell
}
else if let oneTextFieldCell = cell as? OneTextFieldTableViewCell
{
     // configure oneTextFieldCell
}

return cell

一旦添加代码以使单元格出列,这就更加详细了。所以我个人更喜欢并推荐第一种方法。

答案 1 :(得分:3)

在这个问题中有一些不错的答案,但是大多数都有一个共同的坏事,他们强制解包的选项,你应该尽可能多地避免(几乎唯一可以接受的地方使用它们在IBOutlets中)

我认为这是解决这个问题的最佳方法:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCellWithIdentifier("Identifier", forIndexPath: indexPath) as? FormItemTableViewCell else {
        fatalError("Cell is not of kind FormItemTableViewCell")
    }

    switch cell {
    case let cell as TwoOptionTableViewCell where indexPath.row == 1:
        // Configure cell, which is an object of class TwoOptionTableViewCell, but only when we are in row 1
        break
    case let cell as TwoOptionTableViewCell:
        // Configure cell, which is an object of class TwoOptionTableViewCell, when the row is anything but 1
        break
    case let cell as OneTextFieldTableViewCell:
        // Configure cell, which is an object of class OneTextFieldTableViewCell
        break
    case _: print("The cell \(cell) didn't match any patterns: \(indexPath)")
    }

    cell.questionLabel.text = "What is the meaning of life?";

    return cell
}

现在让我向您介绍我认为最好的方式。

首先,它并没有强制解开任何选项,所有内容都在switch案例中很好地解开。

它将您的单元格从表格中取消(您应该经常这样做),并确保它是FormItemTableViewCell的子类,否则会引发致命错误。

通过使用switch case,它会将cell转换为您需要的类,同时它会检查它是否是您想要的索引路径。因此,如果要在共享类的不同行中共享某些逻辑,则可以将indexPath.row与多个值进行比较。如果您不使用where子句,它将在找到该类的单元格的所有位置使用相同的逻辑。

请注意,您需要添加一些逻辑以根据行获取所需的标识符。

答案 2 :(得分:1)

如果我理解正确,您希望将单元格的主要声明保留为reshape2以访问公共属性。

您可以创建一个新变量并为其指定演变版本。 用这个实例做你的东西,因为这是一个类对象,它将指向相同的引用。

FormItemTableViewCell

答案 3 :(得分:0)

在这种情况下你必须有条件地施放它们。我喜欢使用Enums for Rows / Sections而不是== 1(取决于你的TableView设置方式),但基本上你想要做以下事情:

if indexPath.row == 1 {
    let cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
    // Note that we cast the cell to TwoOptionTableViewCell
    // access `segControl` here
    return cell
} else {  
  let cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
  // This cell we cast to OneTextFieldTableViewCell. 
  // access `answerTextField` here
  return cell
}

您正在做的是将单元格定义为FormItemTableViewCell,因此后续访问只会在该表单中知道它,即使您在赋值期间将其明确地转换为子类。

作为旁注,您不必像在那里那样分配到var,您可以做的是let cell: FormItemTableViewCell。然后在if语句中,您可以定义子类的新单元格,对它们进行操作,然后分配回原始cell,然后返回它。如果您要在if语句之后对两种单元格类型执行相同的操作(例如设置背景颜色或其他内容,而不管您拥有哪个子类),这将非常有用。

以下是我最喜欢处理这种情况的方法:

enum CellTypes {
  case TwoOption, OneTextField
  init(row: Int) {
    if row == 1 {
      self = .TwoOption
    } else {
      self = .OneTextField
    }
  }

  var reuseIdentifier: String {
    switch self {
    case .TwoOption: return "twoOptionReuseIdentifier"
    case .OneTextField: return "oneTextFieldReuseIdentifier"
    }
  }
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  let cell: FormItemTableViewCell

  let cellType = CellTypes(row: indexPath.row)
  switch cellType {
  case .TwoOption:
    let twoOptionCell = tableView.dequeueReusableCellWithIdentifier(cellType.reuseIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
    // do stuff with the `segControl`
    cell = twoOptionCell
  case .OneTextField:
    let textFieldCell = tableView.dequeueReusableCellWithIdentifier(cellType.reuseIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
    // do stuff with the `answerTextField`
    cell = textFieldCell
  }

  // Here do something regardless of which CellType it is:
  cell.questionLabel.text = "What is the meaning of life?"

  return cell
}