Ios Swift自定义解码,包括另一个自定义解码模型

Ios Swift自定义解码,包括另一个自定义解码模型,ios,swift,decodable,Ios,Swift,Decodable,我目前正在使用Yelp Fusion API构建一个食品应用程序。在我的项目中有两个模型,分别称为Business和BusinessDatail。为了在tableView中列出餐厅,我从后端获取一个餐厅列表,并将其自定义解码为一个Business[Business]数组。然后,当单击业务的tableViewCell时,我获取详细的业务信息并将其自定义解码为BusinessDetail struct Business { let id: String let name: Strin

我目前正在使用Yelp Fusion API构建一个食品应用程序。在我的项目中有两个模型,分别称为Business和BusinessDatail。为了在tableView中列出餐厅,我从后端获取一个餐厅列表,并将其自定义解码为一个Business[Business]数组。然后,当单击业务的tableViewCell时,我获取详细的业务信息并将其自定义解码为BusinessDetail

struct Business {
    let id: String
    let name: String
    let rating: Float?
    let price: String?
    let displayPhone: String?
    let imageUrl: URL
    let category: String
    let reviewCount: Int
    let coordinates: Coordinates
    let address: Address
}
Business和BusinessDetail都是定制的解码模型,目前它们是以这种方式初始化的

extension Business: Decodable {
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case rating
        case price
        case displayPhone = "display_phone"
        case imageUrl = "image_url"
        case category = "categories"
        case reviewCount = "review_count"
        case coordinates
        case address = "location"
        enum CategoryCodingKeys: String, CodingKey {
            case title
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        id = try container.decode(String.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        rating = try container.decode(Float.self, forKey: .rating)
        price = try container.decodeIfPresent(String.self, forKey: .price)
        displayPhone = try container.decodeIfPresent(String.self, forKey: .displayPhone)
        imageUrl = try container.decode(URL.self, forKey: .imageUrl)

        var categoriesContainer = try container.nestedUnkeyedContainer(forKey: .category)
        var tempCategory = ""

        while !categoriesContainer.isAtEnd {
            let categoryContainer = try categoriesContainer.nestedContainer(keyedBy: CodingKeys.CategoryCodingKeys.self)
            let title = try categoryContainer.decode(String.self, forKey: .title)
            tempCategory += tempCategory == "" ? title: ", \(title)"
        }
        category = tempCategory

        reviewCount = try container.decode(Int.self, forKey: .reviewCount)
        coordinates = try container.decode(Coordinates.self, forKey: .coordinates)
        address = try container.decode(Address.self, forKey: .address)
    }
}
下面是业务列表的json

{
    "businesses": [
        {
            "id": "I1D8NHvMWf8oMYceTyLlHg",
            "name": "John Mills Himself",
            "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/OH84e6eP8zpzBECF0WvTXA/o.jpg",
            "is_closed": false,
            "url": "https://www.yelp.com/biz/john-mills-himself-brisbane?adjust_creative=0mCaOEYvfM9_oOaXgMuW6A&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=0mCaOEYvfM9_oOaXgMuW6A",
            "review_count": 55,
            "categories": [
                {
                    "alias": "coffee",
                    "title": "Coffee & Tea"
                },
                {
                    "alias": "bakeries",
                    "title": "Bakeries"
                },
                {
                    "alias": "wine_bars",
                    "title": "Wine Bars"
                }
            ],
            "rating": 4.5,
            "coordinates": {
                "latitude": -27.47151,
                "longitude": 153.025654
            },
            "transactions": [],
            "price": "$",
            "location": {
                "address1": "40 Charlotte St",
                "address2": "",
                "address3": "",
                "city": "Brisbane",
                "zip_code": "4000",
                "country": "AU",
                "state": "QLD",
                "display_address": [
                    "40 Charlotte St",
                    "Brisbane Queensland 4000",
                    "Australia"
                ]
            },
            "phone": "",
            "display_phone": "",
            "distance": 383.2254392716822
        },
        {
            "id": "KaIoCOg-IZJtLdN39Cw__Q",
            "alias": "strauss-brisbane",
            "name": "Strauss",
            "image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/eYKx68uOaEY5k9Jt4TrQPw/o.jpg",
            "is_closed": false,
            "url": "https://www.yelp.com/biz/strauss-brisbane?adjust_creative=0mCaOEYvfM9_oOaXgMuW6A&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=0mCaOEYvfM9_oOaXgMuW6A",
            "review_count": 33,
            "categories": [
                {
                    "alias": "cafes",
                    "title": "Cafes"
                }
            ],
            "rating": 4.5,
            "coordinates": {
                "latitude": -27.469804,
                "longitude": 153.027384
            },
            "transactions": [],
            "price": "$",
            "location": {
                "address1": "189 Elizabeth St",
                "address2": "",
                "address3": "",
                "city": "Brisbane",
                "zip_code": "4000",
                "country": "AU",
                "state": "QLD",
                "display_address": [
                    "189 Elizabeth St",
                    "Brisbane Queensland 4000",
                    "Australia"
                ]
            },
            "phone": "+61732365232",
            "display_phone": "+61 7 3236 5232",
            "distance": 247.3760157828213
        }
}
这是针对单个BusinessDetail的json响应

{
    "id": "I1D8NHvMWf8oMYceTyLlHg",
    "name": "John Mills Himself",
    "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/OH84e6eP8zpzBECF0WvTXA/o.jpg",
    "is_claimed": false,
    "is_closed": false,
    "url": "https://www.yelp.com/biz/john-mills-himself-brisbane?adjust_creative=0mCaOEYvfM9_oOaXgMuW6A&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_lookup&utm_source=0mCaOEYvfM9_oOaXgMuW6A",
    "phone": "",
    "display_phone": "",
    "review_count": 55,
    "categories": [
        {
            "alias": "coffee",
            "title": "Coffee & Tea"
        },
        {
            "alias": "bakeries",
            "title": "Bakeries"
        },
        {
            "alias": "wine_bars",
            "title": "Wine Bars"
        }
    ],
    "rating": 4.5,
    "location": {
        "address1": "40 Charlotte St",
        "address2": "",
        "address3": "",
        "city": "Brisbane",
        "zip_code": "4000",
        "country": "AU",
        "state": "QLD",
        "display_address": [
            "40 Charlotte St",
            "Brisbane Queensland 4000",
            "Australia"
        ],
        "cross_streets": ""
    },
    "coordinates": {
        "latitude": -27.47151,
        "longitude": 153.025654
    },
    "photos": [
        "https://s3-media3.fl.yelpcdn.com/bphoto/OH84e6eP8zpzBECF0WvTXA/o.jpg",
        "https://s3-media1.fl.yelpcdn.com/bphoto/L8dJYv1GCW1m5IvD0M3qXw/o.jpg",
        "https://s3-media4.fl.yelpcdn.com/bphoto/oUH4cJmPRuAs_jv_xRtXQg/o.jpg"
    ],
    "price": "$",
    "hours": [
        {
            "open": [
                {
                    "is_overnight": false,
                    "start": "0630",
                    "end": "1530",
                    "day": 0
                },
                {
                    "is_overnight": false,
                    "start": "0630",
                    "end": "1530",
                    "day": 1
                },
                {
                    "is_overnight": false,
                    "start": "1600",
                    "end": "2100",
                    "day": 1
                },
                {
                    "is_overnight": false,
                    "start": "0630",
                    "end": "1530",
                    "day": 2
                },
                {
                    "is_overnight": false,
                    "start": "1600",
                    "end": "2100",
                    "day": 2
                },
                {
                    "is_overnight": false,
                    "start": "0630",
                    "end": "1530",
                    "day": 3
                },
                {
                    "is_overnight": false,
                    "start": "1600",
                    "end": "2330",
                    "day": 3
                },
                {
                    "is_overnight": false,
                    "start": "0630",
                    "end": "1530",
                    "day": 4
                },
                {
                    "is_overnight": false,
                    "start": "1600",
                    "end": "2330",
                    "day": 4
                },
                {
                    "is_overnight": false,
                    "start": "1600",
                    "end": "2330",
                    "day": 5
                }
            ],
            "hours_type": "REGULAR",
            "is_open_now": true
        }
    ]
}
正如您所看到的,BusinessDetail与顶部的Business具有完全相同的信息,我希望更改BusinessDetail,如下所示


但是,我不确定这在技术上是否可行。

这里是一个概念性的示例,但您可以将相同的原则应用到您的案例中,使用以下JSON:

{ "a": 1, "b": 2, "c": "three" }
这些模型:

struct Smaller: Decodable {
  var a, b: Int
}

struct Larger: Decodable {
  var smaller: Smaller
  var c: String
}
解码较小的不需要任何额外工作,即不需要手动实现initfrom:Decoder初始值设定项:

let decoder = JSONDecoder()
let small = try! decoder.decode(Smaller.self, from: jsonData)
但对于较大的,您需要手动执行以下操作:

struct Larger: Decodable {
  var smaller: Smaller
  var c: String

  enum CodingKeys: CodingKey {
     case c
  }

  init(from decoder: Decoder) throws {
     let container = try decoder.container(keyedBy: CodingKeys.self)

     self.smaller = try Smaller.init(from: decoder)
     self.c = try container.decode(String.self, forKey: .c)
  }
}

由于您已经在进行手动解码,但不知道为什么,因为Swift仅通过遵循Decodable为您进行解码,您可以解码业务所需的键/值,创建该对象,并将其分配给BusinessDetails的var business:business属性,因为您正在手动解码,所以可以将BusinessDetails声明为business的子类并使用inheritance@New开发人员:我正在手动解码,因为我想展平一些嵌套的json结构,例如键类别。包括var business:business in BusinessDetail起初似乎是可能的,但BusinessDetail的json在{}中没有业务属性的键。@JinLee-请参见下面的答案,它成功了!我可以说,即使是手动解码,它也能工作。谢谢!
struct Smaller: Decodable {
  var a, b: Int
}

struct Larger: Decodable {
  var smaller: Smaller
  var c: String
}
let decoder = JSONDecoder()
let small = try! decoder.decode(Smaller.self, from: jsonData)
struct Larger: Decodable {
  var smaller: Smaller
  var c: String

  enum CodingKeys: CodingKey {
     case c
  }

  init(from decoder: Decoder) throws {
     let container = try decoder.container(keyedBy: CodingKeys.self)

     self.smaller = try Smaller.init(from: decoder)
     self.c = try container.decode(String.self, forKey: .c)
  }
}