2015-09-09 3 views
1

Я хочу, чтобы определить тип, который может быть сериализован для действительного объекта JSONSwift - определить рекурсивный тип с протоколом

Так, например, если JSON может содержать следующее:

String 
Number 
Array 
Object 
Date 
Boolean 

I хотел бы определить протокол с допустимыми типами

protocol JsonSerializable { 
} 

typealias JSONObject = [String : JsonSerializable] 
typealias JSONArray = [JsonSerializable] 

// foundation implements serializing numbers + strings + dates etc. to JSON 
extension String : JsonSerializable {} 
extension Int : JsonSerializable {} 

// problem with defining dictionary and array of JSON-able types 
extension Dictionary : JsonSerializable {} 
... 

вопрос заключается в том, как я могу убедиться, что словарь содержит только сериализуемые типов (во время компиляции)

+0

Вы используете Swift 2? Это будет возможно, если вы. – ABakerSmith

+0

есть. Как мне пойти ti –

+0

кажется, что это часть этого предложения https://github.com/apple/swift-evolution/blob/master/proposals/0157-recursive-protocol-constraints.md –

ответ

3

Во-первых, я бы порекомендовал вам прочитать Empowering Extensions in Swift 2: Protocols, Types and Subclasses (Xcode 7 beta 2). (Поскольку для бета-версии 2 было несколько незначительных изменений)

Назад к проблеме. Для Array:

extension Array where Element: JsonSerializable { 
    var json: String { ... } 
} 

[1, 2, 3].json  // Valid 
[true, false].json // Invalid; `Bool` doesn't conform to `JsonSerializable`. 

словарь немного сложнее, потому что, как сказано в упомянутой статье:

Действующие правила расширения универсального типа, таким образом, является то, что тип который ссылается после где ключевое слово должно быть классом или протоколом .

Поэтому вы не можете определить, что Key из Dictionary должен быть String. Обходной дано в статье определить StringType протокол:

protocol StringType { 
    var characters: String.CharacterView { get } 
} 
extension String: StringType {} 

Теперь для словаря расширения:

extension Dictionary where Key: StringType, Value: JsonSerializable { 
    var json: String { ... } 
} 

["A": 1, "B": 2].json  // Valid 
[1: "1", 2: "2"].json  // Invalid; `Int` doesn't conform to `StringType`. 
["A": true, "B": false].json // Invalid; `Bool` doesn't conform to `JsonSerializable`. 

В качестве альтернативы, вы можете создать свой собственный JsonArray и JsonDictionary типов, которые бы должны быть подкреплены Array или Dictionary соответственно:

struct JsonArray<Element: JsonSerializable> { 
    private var array: [Element] 
    ... 
} 

extension JsonArray: ArrayLiteralConvertible { 
    init(arrayLiteral elements: Element...) { 
     self.init(array: elements) 
    } 
} 

struct JsonDictionary<Value: JsonSerializable> { 
    private var dictionary: [String: Value] 
    ... 
} 

extension JsonDictionary: DictionaryLiteralConvertible { 
    init(dictionaryLiteral elements: (String, Value)...) { 
     var temp = [String: Value]() 
     for (key, value) in elements { 
      temp[key] = value 
     } 

     self.init(dictionary: temp) 
    } 
} 

let array: JsonArray = [1, 2, 3] 
let dictionary: JsonDictionary = ["A": 1, "B": 2] 
+0

У вас есть обновленный URL-адрес ресурса, который вы связываете в первой строке? – achi