2016-05-05 61 views
2

我想製作泛型類,它將能夠採用Parsable類型或Parsable類型的數組。兩者的邏輯幾乎相同,所以我不想爲這個操作創建兩個不同的類。是否有可能使用Swift泛型或協議關聯類型來解決它?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 
    } 
} 

在我目前的執行情況,我使用枚舉,看起來有點醜:

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 
     ... 
    } 
} 
+1

你需要展示你如何接受輸入(兩種情況都不顯示它)和輸出差異是什麼(你的兩個例子返回一個單獨的T,如果這是有意或無意的,我不清楚)。 – zneak

+0

我更新了問題。 – mientus

回答

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) 
    } 
} 

我改名objectFromDictionaryparse因爲它需要採取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 

我希望這會有所幫助。

+0

非常感謝,這就是我一直在尋找的。 – mientus

1

據我所知,類型約束系統的設計並不是爲了處理約束條件。但是,它應該仍然可以做你想問的問題。

一種方法是在單一類型下代表單身人士ParsablesParsables的集合,您可以使用該類型約束ParseOperation。最簡單的方法是擴展Array(或SequenceType,CollectionType等)以符合Parsable類型,但是從Xcode 7.3開始可以使用this is not yet possible。您可以從鏈接的問題使用相同的解決方法,並添加一箇中間類來表示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 
    } 
} 
+0

這是現在我期望它的工作方式,ParsableArray採用Parsable對象的數組,但沒有解析它,只是我指向Parsable類將解析數據,所以它不可能通過[Parsable]對象在這裏。所以可能它現在不能完成.. – mientus

+0

'ParsableArray'應該是通用的,否則你會失去類型安全 – redent84

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))