swift - 通用 Controller 内的通用 Swift 协议(protocol)

标签 swift generics protocols type-alias associated-types

是否可以在泛型中包含泛型?

我有这个协议(protocol)

public protocol ListViewModelProtocol {
    typealias ViewModel
    typealias Cell

    func titleForHeaderInSection(section: Int) -> String?
    func numberOfSections() -> Int
    func numberOfRowsInSection(section: Int) -> Int
    func viewModelAtIndexPath(indexPath: NSIndexPath) -> ViewModel
}

我也有基地ListViewModel实现此协议(protocol)

public class BaseListViewModel<T, U> : ListViewModelProtocol  {
}

但这里已经说我的 ListViewModelProtocol没有实现。如何将 T 和 U 设置为协议(protocol)内的特定类?因为如果我把这个写在协议(protocol)中

typealias ViewModel: CustomClass
typealias Cell: CustomCell

它仍然无法工作。

我的目标是子类 BaseListViewModel喜欢

public class TestListViewModel : BaseListViewModel<TestCellViewModel, TestTableViewCell> { 
}

然后我可以在我的 BaseViewController 中执行此操作

public class BaseViewController<T: ListViewModelProtocol>: UITableViewController  {
}

在某些子类中 ViewController这样做:

public class CustomViewController: BaseViewController<TestListViewModel>  {
}

这样CustomViewController会“得到”TestCellViewModelTestTableViewCell (实际上是它的 BaseViewController)。

但是这当然没有像我预期的那样工作。我缺少什么?或者我必须定义 typealias对于 ListViewModelProtocol在每个实现它或将其用作泛型类型的类中?这意味着我必须定义 ViewModelCellListViewModelProtocol两者皆 BaseListViewModel类和BaseViewController类,但这不是那么通用,因为我只想将这些基类型放入协议(protocol)中,仅此而已。

或者我的方法可能有问题,我应该以不同的方式实现它?

任何建议都是有用的。谢谢

编辑

我已经设法解决了这个问题,但我还有另一个问题。

    public class BaseViewController<T: ListViewModelProtocol>: UITableViewController  {
         var dataSource: T?
    }

此数据源通过调用其自己的方法在 UITableViewDataSource 方法内使用(请参阅 ListViewModelProtocol 方法)。一切工作正常,但是当一些自定义 Controller 时:

Controller: BaseViewController<TestListViewModel>

正在取消初始化,我收到 EXC_BAD_ACCESS 错误。如果我放

deinit {
    self.dataSource = nil
}

它有效,但我想知道为什么我需要将其设置为 nil。

谢谢。

最佳答案

typealias 关键字有多种含义...

// protocol can't be generic
protocol P {
    // here typealias is just placeholder, alias
    // for some unknown type
    typealias A
    func foo(a:A)->String
}

// C is generic
class C<T>:P {
    // here typealias define the associated type
    // in this example it is some generic type
    typealias A = T
    func foo(a: A) -> String {
        return String(a)
    }
}

let c1 = C<Int>()
print(c1.foo(1))     // 1

let c2 = C<Double>()
print(c2.foo(1))     // 1.0

// D is not generic!!!
class D: C<Double> {}

let d = D()
print(d.foo(1)) // 1.0

更新,回答讨论中的问题

class Dummy {}

protocol P {
    // here typealias is just placeholder, alias
    // for some inknown type
    typealias A : Dummy
    func foo(a:A)->String
}

// C is generic
class C<T where T:Dummy>:P {
    // here typealias define the associated type
    // in this example it is some generic type
    typealias SomeType = T
    func foo(a: SomeType) -> String {
        return String(a)
    }
}

class D:Dummy {}
let c = C<D>()
print(c.foo(D())) // D

// now next line doesn't compile
let c1 = C<Int>() // error: 'C' requires that 'Int' inherit from 'Dummy'

关于swift - 通用 Controller 内的通用 Swift 协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34859516/

相关文章:

swift - 为什么我需要强制向下转换才能使用具有约束的协议(protocol)数组

ios - 动画 UISwitch 'onTintColor' 属性

swift - 通用功能中未识别协议(protocol)一致性

protocols - 什么是 SMPP 协议(protocol)?

java - 关于使用Java泛型的错误: "type parameter S is not within its bound"

java - 返回泛型扩展两种类型的工厂方法

ios - 为什么我的简单 swift 委托(delegate)和协议(protocol)设置不起作用?

ios - Gamescene.sks 和 GameScene.swift 在我的项目中似乎没有关联

在 Swift 中编码时出现 Python 错误 : unexpected indent (Xcode 11)

objective-c - 如何调用接受 block 字典作为 Swift 参数的 Objective-C 函数?