【问题标题】:Swift: Generic Protocol Cannot invoke with an argument list of typeSwift:通用协议无法使用类型的参数列表调用
【发布时间】:2018-03-02 07:41:15
【问题描述】:

尝试创建具有关联类型的通用协议。

当我尝试从委托访问方法时出现错误:

Cannot invoke 'numberOfSections' with an argument list of type '(containerView: UITableView)'

代码:

protocol ViewDelegate: class {

    associatedtype ContainerView  
    associatedtype Model 

    func numberOfSections(containerView: ContainerView)
    func aMethodThatTakesNoArugments()
}

class ViewController: UIViewController {

    var newView = AnyView<ViewController>()

    override func viewDidLoad() {
        super.viewDidLoad()
        newView.delegate = self
    }
}

extension ViewController: ViewDelegate {
    typealias ContainerView = UITableView  
    typealias Model = Int

    func numberOfSections(containerView: ContainerView) {
        // do something with containerView
    }

    func aMethodThatTakesNoArugments() {}
}

class AnyView<Delegate: ViewDelegate>: UIView {

    weak var delegate: Delegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func getData() {
        delegate?.aMethodThatTakesNoArugments()  // This compiles fine
        delegate?.numberOfSections(containerView: UITableView()) // Get a compiler error on this line (I am passing an argument):
        // Cannot invoke 'numberOfSections' with an argument list of type '(containerView: UITableView)'
    }
}

我觉得我错过了什么。不带参数的方法编译得很好;但是,如果我调用一个带有参数的方法,我会得到一个编译错误。

【问题讨论】:

  • 我不明白你在尝试什么。您的 ViewDelegate 没有定义 numberOfSections。为什么你认为你可以调用它?
  • 对不起。我试图进一步简化并犯了一个错误。固定。
  • 我明白了。我没有时间写答案,但是当您将类声明为AnyView&lt;Delegate: ViewDelegate&gt; 时,Delegate 可能是符合ViewDelegate 的任何类型。它的关联类型可能不是UITableView。为泛型参数Delegate添加约束。
  • 谢谢。对不起,能不能详细点。你的意思是使用where 子句吗?但是我应该在哪里添加呢?
  • 只是一个快速的设计要点,看起来您正在尝试使用类型擦除将某种 UITableView 功能填充到普通的 UIView 中。如果那是您的目标,我强烈建议您转向另一个方向并制作 UIView 的专门 子类,而不是尝试建立更通用的 View 和 Delegate 连接,以应对看似特殊的情况。

标签: swift xcode generics swift4


【解决方案1】:

您的错误是由于编译器无法判断类型 ContainerView 应该是什么。

您只是为ViewController 定义它,但Delegate 实际上可以是任何类或结构,而不仅仅是ViewController。

有很多方法可以解决这个问题,但不清楚你到底想在这里完成什么,所以我只举几个例子:

正如@OOPer 提到的,您可以约束您的Delegate 泛型以强制符合UITableView:

class AnyView<Delegate: ViewDelegate>: UIView where Delegate.ContainerView == UITableView

类似的选择是简单地定义具有所需类型的协议:

protocol ViewDelegate: class {
    func numberOfSections(containerView: ContainerView)
    func aMethodThatTakesNoArugments()
}

如果您需要更大的灵活性,另一种选择是添加另一个通用类型:

class AnyView<Delegate: ViewDelegate, ContainerViewType>: UIView where Delegate.ContainerView == ContainerViewType

【讨论】:

  • 谢谢!我也不喜欢将已知的UITableView 或UICollectionView 传递给UIView 的想法;但是,这不是我的设计决定,而是必须顺其自然。如果我想灵活地将UITableView 或UICollectionView 传递给ViewDelegate,你会推荐我使用什么
  • 如果你想使用associatedtype,你必须知道类型是什么。您的选择是摆脱关联类型,将特定类型传递到您使用它的位置,不使用它们,或者将关联类型限制为您的所有消费者共有的类型。 (可以使用其他协议)
  • 谢谢。我可以将其限制为多种类型吗? UITableView 或 UICollectionView
  • 不,但你可以创建一个Protocol 来遵守和约束它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-20
  • 2016-10-09
  • 1970-01-01
相关资源
最近更新 更多