在Swift中使用ObjectMapper中的TranfsformType映射类对象

时间:2019-02-20 09:21:56

标签: json swift objectmapper

我有一个JSON

{
  "code": 200,
  "status": "success",
  "data": [
    {
      "cardTypeId": 1,
      "cardInfo": {
        "background": "#4267b2",
        "userName": "abkur_rt",
        "text": "Hello Video",
        "media": {
          "mediaUrl": "",
          "mediaType": "image",
          "mediaThumbUrl": ""
        }
      }
    },
    {
      "cardTypeId": 4,
      "cardInfo": {
        "text": "Image and text",
        "media": {
          "mediaUrl": "",
          "mediaType": "image",
          "mediaThumbUrl": ""
        }
      }
    }
  ]
}

要对此进行解析,我使用了ObjectMapper(https://github.com/tristanhimmelman/ObjectMapper) 我的查询是,在我的JSON中,我根据cardInfo得到cardTypeId,所以我制作了一些类,引用此链接ObjectMapper how to map different object based on JSON来了解如何为类使用自定义TransformType。在链接的JSON响应中,数组为Array,但在我的情况下,如果cardTypeId为1,则另外还有2个字段,与cardInfo中的所有内容相同。所以我做了如下的类,但是我不确定如何创建继承TransFormType的类。

class LBDetailsList: Mappable {

    var lbListArray : [LBDetail]?

    required init?(map: Map) {

    }

    func mapping(map: Map) {
        lbListArray <- map ["data"]
    }
}
class LBDetail: Mappable {
    var cardTypeID : Int?
    var cardInfo: LBBaseCardInfo?

    required init?(map: Map) {

    }

    func mapping(map: Map)
    {
        cardInfo <- map["cardInfo"]
    }
}
class LBBaseCardInfo: Mappable {

    var text: String?
    var media: LBMedia?

    required init?(map: Map) {

    }

    func mapping(map: Map) {
        text <- map["text"]
        media <- map["media"]
    }
}
class CardType1: LBBaseCardInfo {

    var background, userName : String?

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

    override func mapping(map: Map) {
        super.mapping(map: map)
        background <- map["background"]
        userName <- map["userName"]
    }
}
class CardType2: LBBaseCardInfo {

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

    override func mapping(map: Map) {
        super.mapping(map: map)
    }
}
class LBMedia: Mappable {

    var mediaURL: String?
    var mediaType: String?
    var mediaThumbURL: String?

    required init?(map: Map) {

    }

    func mapping(map: Map) {
        mediaURL <- map["mediaUrl"]
        mediaType <- map["mediaType"]
        mediaThumbURL <- map["mediaThumbUrl"]
    }
}

请帮助我了解该框架。

2 个答案:

答案 0 :(得分:0)

您需要按以下方式创建。

1)BaseClass:

struct BaseClass : Mappable {
    var code : Int?
    var status : String?
    var data : [CardData]?

    init?(map: Map) {

    }

    mutating func mapping(map: Map) {

        code <- map["code"]
        status <- map["status"]
        data <- map["data"]
    }
}

2)CardData:

struct CardData : Mappable {
    var cardTypeId : Int?
    var cardInfo : CardInfo?

    init?(map: Map) {

    }

    mutating func mapping(map: Map) {

        cardTypeId <- map["cardTypeId"]
        cardInfo <- map["cardInfo"]
    }
}

3)媒体:

struct Media : Mappable {
    var mediaUrl : String?
    var mediaType : String?
    var mediaThumbUrl : String?

    init?(map: Map) {

    }

    mutating func mapping(map: Map) {

        mediaUrl <- map["mediaUrl"]
        mediaType <- map["mediaType"]
        mediaThumbUrl <- map["mediaThumbUrl"]
    }
}

4)CardInfo:

struct CardInfo : Mappable {
    var background : String?
    var userName : String?
    var text : String?
    var media : Media?

    init?(map: Map) {

    }

    mutating func mapping(map: Map) {

        background <- map["background"]
        userName <- map["userName"]
        text <- map["text"]
        media <- map["media"]
    }
}

我已经基于您的json创建了以下Mappable结构。如果您的json不包含任何键,则它将使用nil值解析json。

我为您的CardInfo设置了var text : String?,这意味着,如果没有可用的密钥,则将使用nil解析json。因此,在使用此功能时,必须要求在展开前检查是否为nil。

我希望这会对您有所帮助。

答案 1 :(得分:0)

我知道它不能从字面上回答这个问题,但这是使用Decodable native 解决方案。

它将键data的数组解码为具有关联值的枚举。这可以非常平滑地处理不同类型。

在枚举中,cardTypeId首先被解码,而在交换机cardInfo中,根据类型ID被解码为相应的结构。

struct Response : Decodable {
    let code : Int
    let status : String
    let data : [CardData]
}

enum CardData  {
    case user(UserData), image(ImageData), unknown
}

extension CardData: Decodable {
    private enum CodingKeys: String, CodingKey {
        case cardTypeId
        case cardInfo
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(Int.self, forKey: .cardTypeId)
        switch type {
        case 1:
            let info = try container.decode(UserData.self, forKey: .cardInfo)
            self = .user(info)
        case 4:
            let info = try container.decode(ImageData.self, forKey: .cardInfo)
            self = .image(info)
        default:
            self = .unknown
        }
    }
}

struct UserData : Decodable {
    let text, userName, background : String
    let media : Media
}

struct ImageData : Decodable {
    let text : String
    let media : Media
}

struct Media : Decodable {
    let mediaUrl, mediaType, mediaThumbUrl : String
}

let jsonString = """
{
  "code": 200,
  "status": "success",
  "data": [
    {
      "cardTypeId": 1,
      "cardInfo": {
        "background": "#4267b2",
        "userName": "abkur_rt",
        "text": "Hello Video",
        "media": {
          "mediaUrl": "",
          "mediaType": "image",
          "mediaThumbUrl": ""
        }
      }
    },
    {
      "cardTypeId": 4,
      "cardInfo": {
        "text": "Image and text",
        "media": {
          "mediaUrl": "",
          "mediaType": "image",
          "mediaThumbUrl": ""
        }
      }
    }
  ]
}
"""

let data = Data(jsonString.utf8)

do {
    let result = try JSONDecoder().decode(Response.self, from: data)
    let cardData = result.data
    for item in cardData {
        switch item {
        case .user(let userData) : print(userData)
        case .image(let imageData) : print(imageData)
        case .unknown: print("unknown")
        }
    }
} catch {
    print(error)
}