【问题标题】:Mapping class object using TranfsformType in ObjectMapper in Swift在 Swift 的 ObjectMapper 中使用 TranfsformType 映射类对象
【发布时间】:2019-07-13 22:23:16
【问题描述】:

我有一个 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"]
    }
}

请帮助我理解这个框架。

【问题讨论】:

  • 在 Swift 4+ 中,所有用于将 JSON 解析为对象的第三方库都已过时,取而代之的是 Codable 协议。我们鼓励您放弃ObjectMapper 并使用Codable
  • 感谢您的通知,但我现在必须继续这样做,然后肯定会在不久的将来进行更改。
  • 我现在就改变。使用Codable 可以更轻松地解码不同类型

标签: json swift objectmapper


【解决方案1】:

您需要按照以下方式创建。

1) 基类:

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) 卡片信息:

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 创建了以下可映射结构。如果您的 json 没有包含任何键,那么它将解析 json 值为 nil。

对于您的CardInfo,我设置了var text : String?,这意味着,如果没有此密钥,则将使用 nil 解析 json。所以当你使用这个时,你必须在 unwrap 之前检查 not nil。

希望对你有所帮助。

【讨论】:

  • 如您所说,如果您的 json 不包含任何键,那么它将解析 json 值为 nil。这是我不想要的。我有近 20 种类型,我只在这里展示了 2 种,所以如果我使用这种方法,我将不得不添加所有在 CardInfo 类中不同的键,然后对于每张卡片,我将有变量为零。我很感激尝试提供帮助,但是我已经使用过这种方法,并且想通过使用 ObjectMapper 中的 TransforType 来学习一种新方法。
  • 因为你的 JSON 不是固定的,你不能假设哪个会来。您必须要求添加所有密钥。
  • 请检查此链接。这可能会让你知道我到底想要什么。 stackoverflow.com/questions/43269448/…
  • 您有使用上述链接的解决方案吗? :)
  • 我无法创建类似于AnimalsArrayTransformType 的类,因为他的示例在数组中具有不同的键,而在我的情况下,我的类具有不同的键,具体取决于卡片类型。这可以使用该链接来实现,但我不确定如何实现它。
【解决方案2】:

我知道它并没有从字面上回答问题,但这是使用Decodablenative 解决方案。

它将键 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)
}

【讨论】:

  • 感谢您的回答。这个例子肯定会给我新的机会来了解Codable,但我真的很想知道和学习如何使用 ObjectMapper 的 TransforType。
猜你喜欢
  • 2018-04-29
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 2019-02-12
相关资源
最近更新 更多