简体   繁体   English

Swift ObjectMapper 类型推断

[英]Swift ObjectMapper type inference

Dear Stackoverflowers,亲爱的 Stackoverflowers,

I have a hindrance regarding using ObjectMapper, so lets get straight to the point.我在使用 ObjectMapper 时遇到了障碍,所以让我们直接切入正题。

I'm saving models as a temporary record in a SQLite table, in JSON form.我将模型以 JSON 格式保存为 SQLite 表中的临时记录。 Each model has a Type field that uniquely identifies to which Model type it maps to.每个模型都有一个类型字段,用于唯一标识它映射到的模型类型。

For instance, if we have Models Dog, Cat, Mouse conforming to the Animal protocol, there's a equivalent AnimalType (DogType, CatType, MouseType) enum, which is also a field in each of the Models.例如,如果我们有符合 Animal 协议的模型狗、猫、鼠标,则有一个等效的 AnimalType (DogType, CatType, MouseType) 枚举,它也是每个模型中的一个字段。 Once saved to the database, I'm having trouble figuring out a elegant way of mapping the JSON loaded from the database to an actual instance of a Model class.一旦保存到数据库中,我就无法找到一种优雅的方法来将 JSON 从数据库加载到 Model 类的实际实例。

What I'm currently doing is converting the JSON via NSJSONSerialization into a JSON dictionary and querying the dictionary for the Type.我目前正在做的是通过 NSJSONSerialization 将 JSON 转换为 JSON 字典并查询该字典的类型。 Once the Type's found, I switch through all Types, instantiating a related Mapper object and attempting to deserialize the object.找到类型后,我会切换所有类型,实例化相关的 Mapper 对象并尝试反序列化该对象。 I feel this is a brute-force approach and was thinking there might be a better way of approach this problem.我觉得这是一种蛮力方法,并且认为可能有更好的方法来解决这个问题。

Conclusive :结论

Models : Dog, Cat, Mouse (conforming to Animal, has AnimalType requirement)模型:狗,猫,老鼠(符合动物,有动物类型要求)

Enums : AnimalType (DogType, CatType, MouseType)枚举:AnimalType(DogType、CatType、MouseType)

Problem : How to determine and correctly instantiate a Mapper object to deserialize the loaded JSON into a instance, other than manually inspecting each Type and instantiating a correct mapper.问题如何确定并正确实例化 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
}
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)
}

I wrote this while looking for a Swift equivalent of @JsonSubTypes from Jackson for polymorphic mapping of JSON subclasses.我在寻找 Jackson 的@JsonSubTypes的 Swift 等价物时写了这个,用于 JSON 子类的多态映射。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM