2016-05-03 20 views
2

親愛なるStackoverflowers、スウィフトObjectMapperの型推論

私はそうはポイントにまっすぐに取得することができます、ObjectMapperを使っに関する障害を持っています。

モデルをJSON形式のSQLiteテーブルに一時的なレコードとして保存しています。各モデルには、どのモデルタイプにマップするかを一意に識別するタイプフィールドがあります。

たとえば、Animalプロトコルに準拠したモデルDog、Cat、Mouseがある場合、各モデルのフィールドでもある同等のAnimalType(DogType、CatType、MouseType)列挙型があります。いったんデータベースに保存すると、データベースからロードされたJSONをModelクラスの実際のインスタンスにマッピングするうまい方法を見つけ出すことができません。

私が現在行っていることは、JSONをNSJSONSerialization経由でJSON辞書に変換し、その型の辞書を照会することです。タイプが見つかると、すべてのタイプを切り替えて、関連するマッパーオブジェクトをインスタンス化し、オブジェクトをデシリアライズしようとします。私はこれがブルートフォースのアプローチだと思っており、この問題へのより良いアプローチがあるかもしれないと考えていました。

決定的

モデル:犬、猫、マウス(動物に準拠し、AnimalType要件を有する)

列挙:AnimalType(DogType、CatType、MOUSETYPE)

問題Mapperオブジェクトを特定して正しくインスタンス化して、ロードされたJSONをデシリアライズして手動で各タイプを検査し、正しいマッパーをインスタンス化する以外の方法があります。

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 
} 

答えて

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

JSONサブクラスの多型マッピングのためのジャクソンから@JsonSubTypesのスウィフトと同等を探している間、私はこれを書きました。