Swift ObjectMapper 类型推断
Swift ObjectMapper type inference
亲爱的 Whosebugers,
我在使用 ObjectMapper 方面遇到了障碍,所以让我们开门见山。
我将模型保存为 SQLite table 中的临时记录,格式为 JSON。每个模型都有一个类型字段,用于唯一标识它映射到的模型类型。
例如,如果我们有符合 Animal 协议的模型 Dog、Cat、Mouse,则有一个等效的 AnimalType (DogType、CatType、MouseType) 枚举,它也是每个模型中的一个字段。保存到数据库后,我很难找到一种优雅的方法来将从数据库加载的 JSON 映射到模型 class.
的实际实例
我目前正在做的是通过 NSJSON 序列化将 JSON 转换为 JSON 字典,并在字典中查询类型。找到类型后,我会切换所有类型,实例化相关的 Mapper 对象并尝试反序列化该对象。我觉得这是一种蛮力方法,并且认为可能有更好的方法来解决这个问题。
结论:
模型:狗、猫、老鼠(符合动物,有动物类型要求)
枚举: AnimalType (DogType, CatType, MouseType)
问题:如何确定并正确实例化 Mapper 对象以将加载的 JSON 反序列化为实例,而不是手动检查每个 Type并实例化一个正确的映射器。
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
}
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)
}
我在寻找 Swift 等同于 Jackson 的 @JsonSubTypes
用于 JSON 子类的多态映射时写了这篇文章。
亲爱的 Whosebugers,
我在使用 ObjectMapper 方面遇到了障碍,所以让我们开门见山。
我将模型保存为 SQLite table 中的临时记录,格式为 JSON。每个模型都有一个类型字段,用于唯一标识它映射到的模型类型。
例如,如果我们有符合 Animal 协议的模型 Dog、Cat、Mouse,则有一个等效的 AnimalType (DogType、CatType、MouseType) 枚举,它也是每个模型中的一个字段。保存到数据库后,我很难找到一种优雅的方法来将从数据库加载的 JSON 映射到模型 class.
的实际实例我目前正在做的是通过 NSJSON 序列化将 JSON 转换为 JSON 字典,并在字典中查询类型。找到类型后,我会切换所有类型,实例化相关的 Mapper 对象并尝试反序列化该对象。我觉得这是一种蛮力方法,并且认为可能有更好的方法来解决这个问题。
结论:
模型:狗、猫、老鼠(符合动物,有动物类型要求)
枚举: AnimalType (DogType, CatType, MouseType)
问题:如何确定并正确实例化 Mapper 对象以将加载的 JSON 反序列化为实例,而不是手动检查每个 Type并实例化一个正确的映射器。
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
}
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)
}
我在寻找 Swift 等同于 Jackson 的 @JsonSubTypes
用于 JSON 子类的多态映射时写了这篇文章。