Ios 如何使用if语句将变量类型设置为特定类型的自定义tableCell?

Ios 如何使用if语句将变量类型设置为特定类型的自定义tableCell?,ios,swift,uitableview,protocols,Ios,Swift,Uitableview,Protocols,我有三种不同类型的自定义UITableCell。我有一个if语句来设置它们: override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if somePosts[indexPath.row].typeOfPost == .linkPost { let cell: LinkTableV

我有三种不同类型的自定义UITableCell。我有一个if语句来设置它们:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {                
    if somePosts[indexPath.row].typeOfPost == .linkPost {
        let cell: LinkTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "linkTableViewCell") as! LinkTableViewCell

    } else if somePosts[indexPath.row].typeOfPost == .picturePost {
        let cell: PictureTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "pictureTableViewCell") as! PictureTableViewCell

    } else if somePosts[indexPath.row].typeOfPost == .textPost {
        let cell: TextTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "textTableViewCell") as! TextTableViewCell


    } else {
        print("Type of post is not link, picture, or text")
    }
}
每个自定义单元格都有类似的标签,如标题和时间。我希望使用同一行代码设置这些标签,例如:

cell.titleLabel.text = "Some title here"

然而,在这个例子中,我得到一个错误,说我使用了一个未解析的标识符“cell”,显然是因为我的变量被声明为非全局的。既然swift是强类型的,有没有办法解决这个问题?谢谢

您有三个基本解决方案

  • 在每个块内重复
    cell.text=…
    。但这并不是你在问题中所说的你真正想要的
  • 让您的三个自定义单元类都扩展一个公共基类。让这个基类定义任何公共属性
  • 使用公共属性定义协议,并使每个自定义单元格类符合该协议
  • 对于选项2和3,您将在第一个
    if
    语句之前声明一个基本/协议类型的变量。然后在整个
    if/else
    块之后,可以指定任何公共属性

    如果需要更新任何特定于单元类型的属性,也可以在相应的块内进行更新

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell: BaseTableViewCell?
        if somePosts[indexPath.row].typeOfPost == .linkPost {
            cell = self.tableView.dequeueReusableCell(withIdentifier: "linkTableViewCell") as! LinkTableViewCell
        } else if somePosts[indexPath.row].typeOfPost == .picturePost {
            cell = self.tableView.dequeueReusableCell(withIdentifier: "pictureTableViewCell") as! PictureTableViewCell
        } else if somePosts[indexPath.row].typeOfPost == .textPost {
            cell = self.tableView.dequeueReusableCell(withIdentifier: "textTableViewCell") as! TextTableViewCell
        } else {
            print("Type of post is not link, picture, or text")
        }
    
        if let cell = cell {
            cell.commonProperty = ...
    
            return cell
        } else {
            return nil // this shouldn't happen but if it does, you have a bug to fix
        }
    }
    

    如果每个子类都有自己的titleLabel属性,则需要使它们都符合协议。我们称之为
    ConfigurableCell

    protocol ConfigurableCell {
        var titleLabel: UILabel { get set }
    }
    
    然后,您可以以相同的方式初始化单元格,但将其声明为
    ConfigurableCell

    var cell: ConfigurableCell? = nil    // not set yet
    if somePosts[indexPath.row].typeOfPost == .linkPost {
        cell = self.tableView.dequeueReusableCell(withIdentifier: "linkTableViewCell") as! LinkTableViewCell
    } else if somePosts[indexPath.row].typeOfPost == .picturePost {
        cell = self.tableView.dequeueReusableCell(withIdentifier: "pictureTableViewCell") as! PictureTableViewCell
    } else if somePosts[indexPath.row].typeOfPost == .textPost {
        cell = self.tableView.dequeueReusableCell(withIdentifier: "textTableViewCell") as! TextTableViewCell
    } 
    
    guard let cell = cell else {
        // how to handle this error case is up to you
        print("Type of post is not link, picture, or text")
        return UITableViewCell()    
    }
    
    // now, cell is a ConfigurableCell with a titleLabel property, regardless of class
    cell.titleLabel.text = "Some title"
    

    当然,
    UITableViewCell
    确实有一个内置的
    textLabel
    属性,您可以尝试在单元格类中使用该属性,然后就不需要协议了,因为该属性位于
    UITableViewCell
    中,它可以创建一个协议供TableViewCell类扩展,并将
    单元格
    存储为该类型的变量

    protocol ConfigurableCell {
        var titleLabel: UILabel { get set }
    }
    
    protocol MyTableViewCell {
        var titleLabel: UILabel { get }
        // ...
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let identifier: String
    
        switch somePosts[indexPath.row].typeOfPost {
            case .linkPost: identifier = "linkTableViewCell"
            case .picturePost: identifier = "pictureTableViewCell"
            case .textPost: identifier = "textTableViewCell"
            default: fatalError("Type of post is not link, picture, or text")
        }
    
        guard let cell = self.tableView.dequeueReusableCell(withIdentifier: identifier) as? MyTableViewCell else {
            fatalError("Cell isn't castable to MyTableViewCell")
        }
    
        cell.titleLabel.text = "Some title here" 
        // ...
    }
    

    不相关,但从数据源数组中三次检索该类型的代价是不必要的。您应该使用switch语句
    switch-somePosts[indexPath.row].typeOfPost{case.linkPost…
    谢谢,这很有帮助。我对这一点很陌生,所以任何建议都会受到重视这里有这么多重复的代码。停止疯狂。除了瓦迪安说的以外?所有建议都会受到重视;我不是最好的编码员。让我更好!@有人看到我对亚历山大答案的评论。他们会帮助你更好地理解波菲,我是新手,所以如果这是一个愚蠢的问题,请不要杀了我,但是当我声明协议时,我得到了一个错误:“协议中的属性必须有显式的{get}或{get set}说明符。好吧,这修复了这个错误,但是现在我得到了“无法将类型“LinkTableViewCell”(以及所有其他类型的单元格)的值分配给类型ConfigurableCell?”?“您是否使类符合协议?
    class-LinkTableViewCell:UITableViewCell,ConfigurableCell{…
    您需要添加协议一致性(直接或通过扩展)对于所有的表格单元格类型。我强烈建议阅读全文,因为这是理解如何编写好的Swift代码的最重要部分之一。好吧,我真的很烂,我提前道歉。它一直在第二行出现致命错误。但不确定为什么…所有标签都必须相同吗?有些不同nt和一些在每个自定义单元格中都是相同的。我试着这样做,这样相同的就不需要多次键入。@有人忘记让现有类符合这个新协议了吗?@Honey 0。我怀疑他没有创建他的类(
    LinkTableViewCell
    TextTableViewCell
    ,等等)符合MyTableViewCell。1.是的,协议确实需要一个更好的名称,但我对问题域的了解还不够,无法提出建议。2.是的,他的类应该符合此协议,以便能够引用这些类的实例作为
    MyTableViewCell
    ,而不考虑它们的具体类型。3。也许,如果该按钮是协议的逻辑部分。4.苹果公司对此有一个视频。@Honey 5.这是必要的,以便向编译器表示,无论具体类型是什么(
    LinkTableViewCell
    Text…
    Picture…
    )是一个实例,我们可以始终确保它将是一个具有
    标题标签的类型,我们可以使用该类型,而不必关心该类型的任何其他细节。@亲爱的,假设协议不存在,而
    cell
    具有类型
    NSTableViewCell
    。我们在这里处理的所有实例都可以分配给
    cell
    。但是,当我们说
    cell.titleLabel
    时,编译器会给出一个错误。
    NSTableViewCell
    没有
    titleLabel
    ,因此不能保证实例的具体类型有
    titleLabel
    。协议形式化地保证
    titleLabel
    将为
    存在单元格
    ,无论其具体类型如何。