【问题标题】:TableView not conforming to protocolTableView 不符合协议
【发布时间】:2018-11-03 06:22:15
【问题描述】:

我已经建立了一个基本的 CellAssociation 协议。

但是,我添加到协议中的任何内容都会得到:

"Type 'FooTableView' does not conform to protocol 'Cell Association'"

Xcode 似乎给了我一些提示:

"Multiple maching functions named 'register(cellClass:forCellReuseIdentifier:)' with type '(AnyClass?, String) -> ()' (aka '(Optional<AnyObject.Type>, String) -> ()')"

和..

"Rename to 'register(cellClass:forCellReuseIdentifier:)' to satisfy this requirement"

但是,看起来我的注册函数就是这样命名的。

这是 CellAssociation (TableView.swift)

import UIKit

protocol CellAssociation {
    associatedtype Cell: UITableViewCell

    func register()
    func register(cellClass: AnyClass?, forCellReuseIdentifier: String)

    func dequeueReusableCell(for: IndexPath) -> Cell
    func dequeueReusableCell(withIdentifier: String, for: IndexPath) -> UITableViewCell
}

extension CellAssociation {

    func register() {
        register(cellClass: Cell.self, forCellReuseIdentifier: String(describing: Cell.self))
    }

    func dequeueReusableCell(for indexPath: IndexPath) -> Cell {
        return dequeueReusableCell(withIdentifier: String(describing: Cell.self), for: indexPath) as! Cell
    }
}

这是一个试图符合协议的 TableView:

import UIKit

class LineupDraftSortMenuTableView: UITableView, CellAssociation {

    typealias Cell = LineupDraftSortMenuCell

    init() {
        super.init(frame: CGRect.zero, style: .plain)
        setup()
    }

    required convenience init?(coder: NSCoder) {
        self.init()
    }

    func setup() {
        rowHeight = 40
        separatorStyle = .none
        backgroundColor = UIColor.clear
        register()
    }
}

这个类会抛出错误:

"Type 'LineupDraftSortMenuTableView' does not conform to protocol 'CellAssociation'"

和 LineupDraftSortMenuCell

import UIKit

class LineupDraftSortMenuCell: UITableViewCell {

    let optionLabel = DraftboardLabel()
    let iconCheck = UIImageView()

    let borderView = UIView()

    var selectedOption: Bool = false { didSet { toggleIconCheck() } }

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setup()
    }

    required convenience init?(coder: NSCoder) {
        self.init()
    }

    func setup() {
        addSubviews()
        setupSubviews()
        addConstraints()
    }

    func addSubviews() {
        contentView.addSubview(optionLabel)
        contentView.addSubview(iconCheck)
        contentView.addSubview(borderView)
    }

    func setupSubviews() {
        backgroundColor = UIColor.clear
        contentView.backgroundColor = UIColor.clear
        selectionStyle = .none

        optionLabel.font = UIFont.openSans(weight: .Semibold, size: 9)
        optionLabel.textColor = UIColor.white
        optionLabel.letterSpacing = 0.5

        iconCheck.image = UIImage(named: "icon-check")
        iconCheck.contentMode = .scaleAspectFit
        iconCheck.isHidden = !selectedOption

        borderView.backgroundColor = UIColor(0x5c656f)
    }

    func addConstraints() {
        let viewConstraints: [NSLayoutConstraint] = [
            optionLabel.leftRancor.constraintEqualToRancor(rancor: contentView.leftRancor, constant: 20),
            optionLabel.centerYRancor.constraintEqualToRancor(rancor: contentView.centerYRancor),
            iconCheck.widthRancor.constraintEqualToConstant(constant: 12),
            iconCheck.heightRancor.constraintEqualToConstant(constant: 10),
            iconCheck.centerYRancor.constraintEqualToRancor(rancor: contentView.centerYRancor),
            iconCheck.rightRancor.constraintEqualToRancor(rancor: contentView.rightRancor, constant: -20),
            borderView.leftRancor.constraintEqualToRancor(rancor: contentView.leftRancor, constant: 10),
            borderView.rightRancor.constraintEqualToRancor(rancor: contentView.rightRancor, constant: -10),
            borderView.bottomRancor.constraintEqualToRancor(rancor: contentView.bottomRancor),
            borderView.heightRancor.constraintEqualToConstant(constant: 1),
        ]

        optionLabel.translatesAutoresizingMaskIntoConstraints = false
        iconCheck.translatesAutoresizingMaskIntoConstraints = false
        borderView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate(viewConstraints)
    }

    func toggleIconCheck() {
        iconCheck.isHidden = !selectedOption
    }
}

【问题讨论】:

  • 什么是LineupDraftSortMenuCell
  • 我在帖子中添加了类定义,希望对您有所帮助!
  • 检查答案:D

标签: ios swift uitableview uikit


【解决方案1】:

您的协议有这个要求:

protocol CellAssociation {
    func register(cellClass: AnyClass?, forCellReuseIdentifier: String)
}

但是您的表格视图子类 LineupDraftSortMenuTableView 从未实现该方法。所以不符合协议。

也许您假设该函数声明与 UITableView 已经实现的某些内容相匹配,因此 UITableView 子类可以符合您的协议而无需显式实现它。但事实并非如此。 UITableView 已有的方法是:

func register(_ cellClass: AnyClass?, forCellReuseIdentifier identifier: String)

下划线有很大的不同!

因此,如果您重写协议及其扩展以匹配 UITableView 已经实现的内容,您的代码将编译,如下所示:

protocol CellAssociation {
    associatedtype Cell: UITableViewCell
    func register()
    func register(_ cellClass: AnyClass?, forCellReuseIdentifier: String)
    func dequeueReusableCell(for: IndexPath) -> Cell
    func dequeueReusableCell(withIdentifier: String, for: IndexPath) -> UITableViewCell
}

extension CellAssociation {
    func register() {
        register(Cell.self, forCellReuseIdentifier: String(describing: Cell.self))
    }
    func dequeueReusableCell(for indexPath: IndexPath) -> Cell {
        return dequeueReusableCell(withIdentifier: String(describing: Cell.self), for: indexPath) as! Cell
    }
}

一旦你这么说了,就可以说:

class LineupDraftSortMenuTableView: UITableView, CellAssociation {
    // ...
}

【讨论】:

  • dequeueReusableCell 的小更新,在签名中添加indexPath 作为func dequeueReusableCell(withIdentifier identifier: String, for indexPath: IndexPath) -&gt; UITableViewCell
【解决方案2】:

其实最近我也差不多碰到了你的问题,你可以参考一下(Swift: Conforming to protocols using default values)。

因此,参考该参考,这是您的代码的修改版本。

protocol CellAssociation {
    associatedtype Cell: UITableViewCell

    func register(cellClass: AnyClass?, forCellReuseIdentifier: String)
    func dequeueReusableCell(withIdentifier: String, forIndexPath indexPath: IndexPath) -> UITableViewCell
}

extension CellAssociation {

    func register(cellClass: AnyClass? = Cell.self, forCellReuseIdentifier: String = String(describing: Cell.self)) {
        return register(cellClass: cellClass, forCellReuseIdentifier: forCellReuseIdentifier)
    }

    func dequeueReusableCell(withIdentifier: String = String(describing: Cell.self), forIndexPath indexPath: IndexPath) -> UITableViewCell {
        return dequeueReusableCell(withIdentifier: withIdentifier, forIndexPath: indexPath)
    }
}

我所做的是,我已经传递了默认值,因为您已经为它创建了一个不同的方法,这在 extension 中得到了确认。现在,它将确认protocol。如果您还有任何疑问或问题,请告诉我。

【讨论】:

  • 如何调用 dequeueResusableCell(withIdentifier:for indexPath:) 使用 withIdentifier 的默认值但仍输入 indexPath 的值?
  • 还没有,我们将不胜感激!
猜你喜欢
  • 1970-01-01
  • 2017-02-01
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多