Swift泛型类,可以使用元素数组或单个元素

时间:2016-05-05 22:30:19

标签: ios swift generics

我想制作能够采用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
        ...
    }
}

3 个答案:

答案 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 约束而设计的。但是,仍然可以做你要求的事情。

一种方法是在单个类型下表示单个ParsablesParsables的集合,您可以使用它来约束ParseOperation。最好的方法是扩展Array(或SequenceTypeCollectionType等)以符合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))