2016-05-03 11 views
2

Lieber Stackoverflowers,Swift ObjectMapper Typinferenz

Ich habe ein Hindernis in Bezug auf ObjectMapper verwenden, können so gleich auf den Punkt.

Ich speichere Modelle als temporären Datensatz in einer SQLite-Tabelle in JSON-Form. Jedes Modell verfügt über ein Feld Typ, das eindeutig angibt, welchem ​​Modelltyp es zugeordnet ist.

Wenn beispielsweise die Modelle Hund, Katze, Maus dem Animal-Protokoll entsprechen, gibt es eine entsprechende AnimalType-Aufzählung (DogType, CatType, MouseType), die ebenfalls ein Feld in jedem der Modelle ist. Nach dem Speichern in der Datenbank habe ich Probleme, eine elegante Möglichkeit zu finden, den von der Datenbank geladenen JSON einer tatsächlichen Instanz einer Model-Klasse zuzuordnen.

Was ich gerade mache ist die Konvertierung der JSON über NSJSONSerialization in ein JSON-Wörterbuch und die Abfrage des Wörterbuchs für den Typ. Sobald der Typ gefunden ist, wechsle ich alle Typen durch, instanziiere ein verwandtes Mapper-Objekt und versuche, das Objekt zu deserialisieren. Ich denke, dies ist ein Brute-Force-Ansatz und dachte, es könnte eine bessere Möglichkeit geben, dieses Problem anzugehen.

Schlüssige:

Modelle: Hund, Katze, Maus (zum Tier konform, hat AnimalType Anforderung)

Aufzählungen: AnimalType (DogType, CatType, Mousetype)

Problem: Wie Sie ein Mapper-Objekt ermitteln und korrekt instanziieren, um das geladene JSON in ein Verzeichnis zu deserialisieren Instanz, abgesehen von der manuellen Überprüfung jedes Typs und der Instanziierung eines korrekten Mappers.

enum AnimalType { 
    case Dog 
    case Cat 
    case Mouse 
} 

protocol Animal { 
    var animalType: AnimalType { get } 
} 

struct Dog: Animal { 
    var animalType = AnimalType.Dog 
} 

struct Cat: Animal { 
    var animalType = AnimalType.Cat 
} 

struct Mouse: Animal { 
    var animalType = AnimalType.Mouse 
} 

Antwort

1
import ObjectMapper 

enum AnimalType : String { 
    case Cat = "Cat" 
    case Dog = "Dog" 
    case Mouse = "Mouse" 
} 

class Animal: StaticMappable, Mappable { 
    var animalType: AnimalType? 

    required init?(_ map: Map) {} 

    init() {} 

    func mapping(map: Map) { 
     animalType <- (map["animalType"], EnumTransform<AnimalType>()) 
    } 

    static func objectForMapping(map: Map) -> BaseMappable? { 
     let typeString: String? = map["animalType"].value() 
     if let typeString = typeString { 
      let animalType: AnimalType? = AnimalType(rawValue: typeString) 
      if let animalType = animalType { 
       switch(animalType) { 
        case AnimalType.Cat: return Cat() 
        case AnimalType.Dog: return Dog() 
        case AnimalType.Mouse: return Mouse() 
       } 
      } 
     } 
     return Animal() 
    } 
} 

class Cat: Animal { 
    var purr: String? 

    required init?(_ map: Map) { 
     super.init(map) 
    } 

    override init() { 
     super.init() 
    } 

    override func mapping(map: Map) { 
     super.mapping(map) 

     purr <- map["purr"] 
    } 
} 

class Dog: Animal { 
    var bark: String? 
    var bite: String? 

    required init?(_ map: Map) { 
     super.init(map) 
    } 

    override init() { 
     super.init() 
    } 

    override func mapping(map: Map) { 
     super.mapping(map) 

     bark <- map["bark"] 
     bite <- map["bite"] 
    } 
} 

class Mouse: Animal { 
    var squeak: String? 

    required init?(_ map: Map) { 
     super.init(map) 
    } 

    override init() { 
     super.init() 
    } 

    override func mapping(map: Map) { 
     super.mapping(map) 

     squeak <- map["squeak"] 
    } 
} 

class Owner : Mappable { 
    var name: String? 
    var animal: Animal? 

    required init?(_ map: Map) {} 

    func mapping(map: Map) { 
     name <- map["name"] 
     animal <- map["animal"] 
    } 
} 

let catJson = "{\"animalType\":\"Cat\",\"purr\":\"rrurrrrrurrr\"}" 
let cat = Mapper<Cat>().map(catJson) 
if let cat = cat { 
    let catJSONString = Mapper().toJSONString(cat, prettyPrint: false) 
} 

let ownerJson = "{\"name\":\"Blofeld\", \"animal\":{\"animalType\":\"Cat\",\"purr\":\"rrurrrrrurrr\"}}" 
let owner = Mapper<Owner>().map(ownerJson) 
if let owner = owner { 
    let ownerJSONString = Mapper().toJSONString(owner, prettyPrint: false) 
} 

Ich schrieb dieses, während für einen Swift-Äquivalent von @JsonSubTypes von Jackson für polymorphe Mapping von JSON-Subklassen suchen.