我想制作能够采用Parsable类型或Parsable类型的泛型类。两者的逻辑几乎相同,所以我不想为这个操作制作两个不同的类。是否可以使用Swift泛型或协议相关类型来解决它?
protocol Parsable: class {
associatedtype Type
static func objectFromDictionary(dictionary: Dictionary<String, AnyObject>, inContext context: NSManagedObjectContext) -> Type?
func importFromDictionary(dictionary: Dictionary<String, AnyObject>)
}
class ParseOperation<T: Parsable>: NSOperation {
func execute() -> T {
}
}
class ParseOperation<T where T: SequenceType, T.Generator.Element == Parsable>: NSOperation {
func execute() -> T {
// Do parsing
}
}
这就是我想要的工作方式:
class ParseOperation<T where T: SequenceType, T.Generator.Element == Parsable OR T: Parsable>: NSOperation {
func execute() -> T {
// Do parsing
}
}
在我目前的实现中,我使用的enum看起来有点难看:
class ParseOperation<T where T: NSManagedObject, T:Parsable>: NSOperation {
var responseToParse: AnyObject?
var parseType: ParseType
var parsedObjects: [T]?
init(parseType: ParseType) {}
func execute() {
var objects: [NSManagedObject] = []
if self.parseType == .Single {
if let responseToParse = self.responseToParse as? Dictionary<String, AnyObject>,
let parsedObject = T.objectFromDictionary(responseToParse, inContext: localContext) {
objects.append(parsedObject)
}
} else if self.parseType == .Array {
if let responseToParse = self.responseToParse as? Array<Dictionary<String, AnyObject>> {
for dictionary in responseToParse {
if let parsedObject = T.objectFromDictionary(dictionary, inContext: localContext) {
objects.append(parsedObject)
}
}
}
}
self.parsedObjects = objects
...
}
}
答案 0 :(得分:3)
我修改了@RonaldMartin的答案,以显示ParsableArray
可能对您有何帮助。它不需要输入Parsable
元素,只需以这种方式实现parse
函数:
protocol Parsable {
associatedtype T
static func parse(input: AnyObject) -> T?
}
struct ParsableArray<TElement where TElement: Parsable>: Parsable {
static func parse(input: AnyObject) -> [TElement.T]? {
guard let arrayInput = input as? [AnyObject] else {
return nil
}
return arrayInput.flatMap(TElement.parse)
}
}
我已将objectFromDictionary
重命名为parse
,因为需要AnyObject
而非Dictionary
才能解析数组。当然,您可以向context
方法添加parse
或任何您喜欢的内容。
如果Parsable
以这种方式完成,则ParseOperation
变得非常简单:
class ParseOperation<T where T: Parsable>: NSOperation {
let input: AnyObject
var result: T.T?
init(input: AnyObject) {
self.input = input
}
override func main() {
result = T.parse(input)
}
}
然后,您可以通过这种方式解析数组(注意:这只是为了演示如何创建ParseOperation
; S
只是一些Parsable
结构) :
let op = ParseOperation<ParsableArray<S>>(input: [["1": 5, "2": 6], ["3": 10]])
op.main()
var r: [S]? = op.result
我希望,这会有所帮助。
答案 1 :(得分:1)
据我所知,类型约束系统不是为处理 OR 约束而设计的。但是,仍然可以做你要求的事情。
一种方法是在单个类型下表示单个Parsables
和Parsables
的集合,您可以使用它来约束ParseOperation
。最好的方法是扩展Array
(或SequenceType
,CollectionType
等)以符合Parsable
类型,但{{3}从Xcode 7.3开始。您可以使用该链接问题中的相同解决方法,并添加一个中间类来表示Parsable
数组:
class ParsableArray: Parsable {
let array: [Parsable]
init(array: [Parsable]) {
self.array = array
}
// Parsable conformance...
}
现在,您可以将原始协议用于类型约束:
class ParseOperation<T: Parsable>: NSOperation {
func execute() -> T {
// Do parsing
}
}
答案 2 :(得分:0)
理想情况下,您应该可以这样做:
// This DOES NOT compile as of XCode 7.3
extension Array: Parsable where Element: Parsable {
// Parsable implementation
}
但目前无效。
目前你必须依赖一个包装结构:
struct ParsableArray<Element: Parsable>: Parsable {
let array: [Element]
init(_ array: [Element]) {
self.array = array
}
// Parsable implementation
}
您还可以为[Parsable]
数组实现便捷方法:
extension Array where Element: Parsable {
func toParsable() -> ParsableArray<Element> {
return ParsableArray(self)
}
}
所以你可以像这样执行你的方法:
let array = [Parsable]()
parse(array.toParsable()) // Equivalent to: parse(ParsableArray(array))