Ios 我可以让realmresults类将协议用作泛型吗?

Ios 我可以让realmresults类将协议用作泛型吗?,ios,swift,protocols,realm,Ios,Swift,Protocols,Realm,我想创建两个领域模型类和一个协议,这是由两个模型类采用的。例如: class Dog: Object, Animal { dynamic var name = "" } class Cat: Object, Animal { dynamic var name = "" } protocol Animal { var name: String { get } } 在本例中,我创建了两个模型类和一个协议 然而,当我转到实现时,问题出现了。以下代码是在view control

我想创建两个领域模型类和一个协议,这是由两个模型类采用的。例如:

class Dog: Object, Animal {
    dynamic var name = ""
}
class Cat: Object, Animal {
    dynamic var name = ""
}
protocol Animal {
    var name: String { get }
}
在本例中,我创建了两个模型类和一个协议

然而,当我转到实现时,问题出现了。以下代码是在view controller中编写的:

var dogs: Results<Dog>? {
    return try! Realm().objects(Dog)
}
var cats: Results<Cat> {
    return try! Realm().objects(Cat)
}
var狗:结果如何?{
返回try!Realm().objects(Dog)
}
风险评估:结果{
返回try!Realm().objects(Cat)
}
这段代码没有任何问题。但代码如下:

var animals: Results<Animal>? {
    switch currentSegmented { // this is from UISegmentedControl
    case .Cat:  // this is from enum
        return self.cats
    case .Dog:
        return self.dogs
}
var动物:结果?{
开关currentSegmented{//这是来自UISegmentedControl
case.Cat://这是来自enum的
回归自我
案例.狗:
回归自我
}
未编译,错误为:
结果要求动物从对象继承

但是,
Animal
是一个协议,因此不能从
对象继承


仍然可以在这里使用协议吗?

我认为没有一个好的解决方案。Swift中的用户定义泛型是不变的,因此即使
Animal
是一个类,您也不能将
结果
转换为
结果

令人不快的冗长解决方案是围绕不同类型的结果创建显式包装类型:

enum AnimalResultsEnum {
    case DogResults(dogs: Results<Dog>)
    case CatResults(cats: Results<Cat>)
}

class AnimalResults {
    var animals = AnimalResultsEnum.DogResults(dogs: try! Realm().objects(Dog))

    var realm: Realm? {
        switch animals {
        case .DogResults(let dogs):
            return dogs.realm
        case .CatResults(let cats):
            return cats.realm
        }
    }

    var count: Int {
        switch animals {
        case .DogResults(let dogs):
            return dogs.count
        case .CatResults(let cats):
            return cats.count
        }
    }

    subscript(index: Int) -> Animal {
        switch animals {
        case .DogResults(let dogs):
            return dogs[index]
        case .CatResults(let cats):
            return cats[index]
        }
    }

    // ... wrap the rest of the methods needed ...
}
enum animalresultsum{
案例犬结果(犬类:结果)
病例CatResults(cats:结果)
}
类动物结果{
var-animalresultsum.DogResults(狗:try!Realm().objects(狗))
var领域:领域{
交换动物{
案例。狗的结果(让狗):
返回狗王国
案例。CatResults(let-cats):
返回猫咪王国
}
}
变量计数:Int{
交换动物{
案例。狗的结果(让狗):
返回狗。计数
案例。CatResults(let-cats):
返回猫。计数
}
}
下标(索引:Int)->动物{
交换动物{
案例。狗的结果(让狗):
返回狗只〔索引〕
案例。CatResults(let-cats):
回归猫[索引]
}
}
//…包装所需的其余方法。。。
}
您可以通过创建一个半类型的已擦除容器来包装结果,从而使其成为泛型:

class CovariantResults<T: Object> {
    private var base: _CovariantResultsBase<T>

    init<U: Object>(_ inner: Results<U>) {
        base = _CovariantResultsImpl<T, U>(inner)
    }

    subscript(index: Int) -> T {
        return base[index]
    }

    // ... wrap the rest of the methods needed ...
}

class _CovariantResultsBase<T: Object> {
    subscript(index: Int) -> T { fatalError("abstract") }
    // ... wrap the rest of the methods needed ...
}

class _CovariantResultsImpl<T: Object, U: Object>: _CovariantResultsBase<T> {
    private let impl: Results<U>

    init(_ inner: Results<U>) {
        impl = inner
    }

    override subscript(index: Int) -> T {
        return impl[index] as! T
    }

    // ... wrap the rest of the methods needed ...
}

// Used as:
let animals = CovariantResults<Animal>(try! Realm().objects(Dog))
类协变结果{
私有var基:\ u协方差结果基
初始化(内部:结果){
基本=_协方差结果简单(内部)
}
下标(索引:Int)->T{
返回基数[索引]
}
//…包装所需的其余方法。。。
}
类_协方差结果基{
下标(索引:Int)->T{fatalError(“abstract”)}
//…包装所需的其余方法。。。
}
类_convariatresultsiml:_convariatresultsbase{
私有let impl:结果
初始化(内部:结果){
impl=内部
}
覆盖下标(索引:Int)->T{
将impl[index]返回为!T
}
//…包装所需的其余方法。。。
}
//用作:
让动物=协变结果(try!Realm().objects(Dog))

在这种情况下,更好的解决方案是将对象本身子类化,并将其称为动物。从中,您可以将相应的动物子类化。@Shripada我相信这是可行的,但为什么您认为这是一个“更好的解决方案”?不是更好,是正确的解决方案。很明显,这是领域的要求,结果只能包含“Object”sAn Animal子类不会有帮助。Swift泛型是不变的,所以你不能将
结果
转换为
结果
。我认为如果没有总包装类型,这目前是不可能的。@ThomasGoyne啊,你是对的;我不是我把它烘干了,但它不起作用。我不知道你说的“粗包装类型”是什么意思,尽管如此。协变结果的伟大解决方案。谢谢!但我改变了一件事:动物不能是U型。结果不能用协议创建。否则就不会有任何问题。所以我为所有类型创建了基类,我需要用作从对象继承的通用结果,并符合我的协议。像create使用AnimalProtocol并制作类动物:对象,AnimalProtocol,然后使用Animal作为所有其他类的基类。效果非常好!