当前位置 : 主页 > 手机开发 > 其它 >

Swift协议要求属性作为协议

来源:互联网 收集:自由互联 发布时间:2021-06-11
我试图定义一个协议“存储库”,它需要定义几个属性(实现特定协议“DataSource”) 但由于我的真实场景的复杂性,其中一个属性需要是“DataSource”的子协议. 我把问题简化为这个简单的代
我试图定义一个协议“存储库”,它需要定义几个属性(实现特定协议“DataSource”)

但由于我的真实场景的复杂性,其中一个属性需要是“DataSource”的子协议.

我把问题简化为这个简单的代码:

protocol DataSource { }

protocol ExtraDataSouce: DataSource {
    func method1() -> String
}

struct MyDataSource: ExtraDataSouce {
    func method1() -> String {
        return "whatever"
    }
}


protocol Repository {
    var firstDataSource: DataSource { get }
    var secondDataSource: DataSource { get }
}

struct MyRepository: Repository {
    var firstDataSource: DataSource
    var secondDataSource: MyDataSource
}

由于“MyRepository”不符合“存储库”,因此在编译时返回错误.但我认为它实际上…有任何想法为什么它不接受定义为“MyDataSource”的“MyRepository”中的“secondDataSource”?

搜索后我找到了关于你的问题的这些信息(如果我在某处错了或者我错过了什么,请纠正我):

即使在逻辑上你的代码应该工作,当你在MyRepository类中声明它们的类型时,swift编译器也不会分开使用常规或只读协议变量的情况.换句话说,如果要在Repository中编写,代码中的错误就会变得很明显

var secondDataSource: DataSource { get set }

和编译器不分开这种情况.我没有找到完全正确的方法来做你想做的事.但有两种接近的方式:

1)显而易见且可能是最正确的方式 – 在MyRepository中更改secondDataSource类型,并根据需要使用其他变量:

var _secondDataSource: MyDataSource
var secondDataSource: DataSource {
        get {return _secondDataSource}
        set {
            guard let newValue = newValue as? MyDataSource else {
                fatalError("MyRepository: attempt to set DataSource type, MyDataSource type expected")
            }
            _secondDataSource = newValue
        }
    }

2)协议方式的关联类型.在这里我将改进@RaduNunu的答案,因为他的代码中的associatedtype type = DataSource行只有占位符效果,并且他的解决方案允许你选择采用任何类型的secondDataSource,例如String:

protocol Repository {
    associatedtype Type = DataSource
    var firstDataSource: DataSource { get }
    var secondDataSource: Type { get }
}

struct MyRepository: Repository {
    var firstDataSource: DataSource
    var secondDataSource: String // - this is ok!
}

这段代码将编译和工作,但看起来很糟糕.而是键入占位符,您最好使用协议一致性:

protocol Repository {
    associatedtype Type: DataSource
    var firstDataSource: DataSource { get }
    var secondDataSource: Type { get }
}

struct MyRepository: Repository {
    var firstDataSource: DataSource
    //var secondDataSource: String - this line not allowed now
    var secondDataSource: MyDataSource
}

此代码已经非常接近目标.但是,从现在开始您不能将协议用作关联类型,因此声明

var secondDataSource: DataSource

在MyRepository中将无法正常工作.这是使用关联类型的代价:您只能使用符合DataSource的类/枚举/结构类型.

网友评论