2015-09-09 2 views
1

Je veux définir un type qui peut être sérialisé à un objet JSON valideSwift - définir un type récursif avec un protocole

Ainsi, par exemple, si un JSON peut contenir les éléments suivants:

String 
Number 
Array 
Object 
Date 
Boolean 

I souhaite définir un protocole avec les types valides

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 {} 
... 

la question est de savoir comment puis-je faire en sorte que le dictionnaire ne contient des types sérialisables (au moment de la compilation)

+0

Utilisez-vous Swift 2? Ce sera possible si vous êtes. – ABakerSmith

+0

oui. Comment puis-je aller à ti –

+0

semble qu'il fait partie de cette proposition https://github.com/apple/swift-evolution/blob/master/proposals/0157-recursive-protocol-constraints.md –

Répondre

3

Tout d'abord je vous recommande de lire Empowering Extensions in Swift 2: Protocols, Types and Subclasses (Xcode 7 beta 2). (Puisque c'est pour la version bêta 2, il y a eu quelques changements mineurs)

Retour à votre problème. Pour Array:

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

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

Dictionnaire est un peu plus compliqué parce que, comme dit dans l'article mentionné:

Les règles actuelles de l'extension d'un type générique de cette manière est que le type référencé après la où mot-clé doit être une classe ou un protocole .

Par conséquent, vous ne pouvez pas spécifier que le Key du Dictionary doit être un String. La solution donnée dans l'article est de définir un protocole StringType:

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

maintenant pour l'extension Dictionnaire:

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`. 

Sinon, vous pouvez créer vos propres types JsonArray et JsonDictionary, qui serait être soutenu par un Array ou Dictionary respectivement:

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

Avez-vous une URL mise à jour pour la ressource que vous liez dans la première ligne? – achi