我知道之前已经问过这个问题,但我不知道如何解决当前这个问题。我已经使用MultipleChoiceQuestionable
属性定义了一个协议associatedtype
:
protocol Questionable {
var text: String {get set}
var givenAnswer: String? {get set}
}
protocol MultipleChoiceQuestionable: Questionable {
associatedtype Value
var answers: Value { get }
}
struct OpenQuestion: Questionable {
var text: String
var givenAnswer: String?
}
struct MultipleChoiceQuestion: MultipleChoiceQuestionable {
typealias Value = [String]
var text: String
var givenAnswer: String?
var answers: Value
}
struct NestedMultipleChoiceQuestion: MultipleChoiceQuestionable {
typealias Value = [MultipleChoiceQuestion]
var text: String
var answers: Value
var givenAnswer: String?
}
符合此协议的类型以Questionable
形式保存在数组中,如下所示:
// This array contains OpenQuestion, MultipleChoiceQuestion and NestedMultipleChoiceQuestion
private var questions: [Questionable] = QuestionBuilder.createQuestions()
我的代码中的某处我想做类似的事情:
let question = questions[index]
if let question = question as? MultipleChoiceQuestionable {
// Do something with the answers
question.answers = .....
}
这是不可能的,因为Xcode警告我:协议MultipleChoiceQuestionable只能用作通用约束。我一直在寻找如何解决这个问题,因为泛型对我来说很新。显然,Swift在编译期间不知道associatedtype
的类型,这就是抛出此错误的原因。我已经读过关于使用类型擦除但我不知道这是否解决了我的问题。也许我应该使用通用属性,或者我的协议定义错了?
答案 0 :(得分:1)
如果要应用于子协议对象的操作不依赖于关联类型(即既没有通用参数也没有返回泛型类型),则可以引入一个辅助协议,它只公开属性/方法你需要,让你的类型符合该协议,并根据该协议声明protocol MultipleChoiceInfo {
var numberOfAnswers: Int { get }
}
extension MultipleChoiceQuestion: MultipleChoiceInfo {
var numberOfAnswers: Int { return answers.count }
}
// do the same for the other multiple-choice types
。
例如,如果您只想了解有关该问题的一些信息:
let question = questions[index]
if let info = question as? MultipleChoiceInfo {
print(info.numberOfAnswers)
}
然后您可以通过新协议访问问题,如下所示:
protocol MultipleChoiceProcessor {
func process(stringAnswers: [String])
func process(nestedAnswers: [MultipleChoiceQuestion])
}
protocol MultipleChoiceProxy {
func apply(processor: MultipleChoiceProcessor)
}
extension MultipleChoiceQuestion: MultipleChoiceProxy {
func apply(processor: MultipleChoiceProcessor) {
processor.process(stringAnswers: answers)
}
}
正如我所说,如果你不能提供一个抽象的(非通用的)界面,那么这不会起作用。
修改强>
如果您需要处理问题中的通用数据,您可以根据具体的通用类型将逻辑提取到另一个"处理"类型,提供您的问题的接口。然后,每个问题类型将其数据分派到处理器接口:
MultipleChoiceProcessor
只需创建符合if let proxy = question as? MultipleChoiceProxy {
proxy.apply(processor:myProcessor)
}
的类型,然后再次进行类型检查:
telnet demo.wftpserver.com 2222
Trying 199.71.215.197...
Connected to demo.wftpserver.com.
Escape character is '^]'.
SSH-2.0-WingFTPServer
顺便说一句,如果你在实际应用程序中没有更多的协议和结构,你可能也会完全放弃协议的东西......对于这类问题,它似乎有点过度设计。 / p>