Swift Decodable json heterogenous array : I have gone through a couple of questions and answers here on SO, and even though they look similar to my question they dont quiet address my issue, as I have tried a buch of them and yet it is not working. here is my json and the method I have tried and I keep getting an error of "The data couldn’t be read because it isn’t in the correct format."
 
     {
       "status": 1,
       "errorMsg": "success",
       "data": [
       {
      "id": null,
      "subMenuId": null,
      "type": "Coming Feat",
      "data": {
        "link": "/google.com",
        "title": "Google",
        "shortDescription": "This is fun",
        "imageUrl": "",
        "openInNewWindow": false
      },
      "datas": null,
      "component": null
    },
    {
      "id": "wdub208t2ghf0b",
      "subMenuId": "39g3hvb83hb98hv",
      "type": "GoingEvent",
      "data": {
        "eventId": "983gv83hv8hv38",
        "sessionId": null,
        "title": "Fest",
        "iconMarker": "http://google.com/sites.png",
        "isPaid": false,
        "startDT": "2018-07-18T16:00:00Z",
        "endDT": "2018-10-31T22:00:00Z",
        "subTitle": null,
        "startDate": "Oct, 2018",
        "endDate": "Oct, 2018",
        "openTime": "04:00 PM",
        "closeTime": "10:00 PM",
        "thumbnail": "https://static.visit.com/estival23.jpg",
        "verticalFeaturedImageUrl": "",
        "horizontalImageUrl": "",
        "categoryTitle": "Celebration",
        "eventCategories": [
          "394bf3w9fbv93v8",
          "dhvbwuehv80"
        ],
        "locations": [
          {
            "uniqueName": "fest",
            "title": "Got if",
            "area": "",
            "region": "Put it",
            "latitude": 67.14517,
            "longitude": 78.797733,
            "distance": "N/A",
            "startDate": "2018-07-18T16:00:00",
            "endDate": "2018-07-27T22:00:00",
            "distancevalue": 0,
            "duration": "N/A",
            "durationValue": 0,
            "valid": true,
            "hasSet": false
          }
        ],
        "prices": null
      },
      "datas": null,
      "component": null
     }
     ]
    }

      class FeatureData: Decodable {
    
    var link: String?
    var title: String?
    var shortDescription: String?
    var imageUrl: String?
    
    enum CodingKeys: String, CodingKey {
        case link
        case title
        case shortDescription
        case imageUrl
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        link = try container.decode(String.self, forKey: .link)
        title = try container.decode(String.self, forKey: .title)
        shortDescription = try container.decode(String.self, forKey: 
      .shortDescription)
        imageUrl = try container.decode(String.self, forKey: .imageUrl)
     }
    
     init() {
     }
     }


     class FeedFeature: Decodable {
    
    var id: String?
    var subMenuId: String?
    var type: String?
    var data = HomeFeedFeatureData()
    
    enum Codingkeys: String, CodingKey {
        case id
        case subMenuId
        case type
        case data
     }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Codingkeys.self)
        id = try container.decode(String.self, forKey: .id)
        subMenuId = try container.decode(String.self, forKey: .subMenuId)
        type = try container.decode(String.self, forKey: .type)
        data = try container.decode(HomeFeedFeatureData.self, forKey: 
    .data)
    }
    
    init() {
        
     }
     }


       class EventCalendar: Decodable {
    // MARK: Properties
    var eventId: String = ""
    var sessionId: String = ""
    var title: String = ""
    var iconMarker: String?
    var isPaid: Bool = false
    var startDT: String = ""
    var endDT: String = ""
    var subTitle: String = ""
    var startDate: String = ""
    var endDate: String = ""
    var openTime: String = ""
    var closeTime: String = ""
    var thumbnail: String = ""
    var locations: [EventLocation] = []
    var prices: [Price]?
    var categoryTitle: String = ""
    
    var isLoadingCell: Bool = false
    var isSelected: Bool = false

    enum CodingKeys: String, CodingKey {
        case eventId = "eventId"
        case sessionId = "sessionId"
        case title = "title"
        case iconMarker = "iconMarker"
        case isPaid = "isPaid"
        case startDT = "startDT"
        case endDT = "endDT"
        case subTitle = "subTitle"
        case startDate = "startDate"
        case endDate = "endDate"
        case openTime = "openTime"
        case closeTime = "closeTime"
        case thumbnail = "thumbnail"
        case locations = "locations"
        case prices = "prices"
        case categoryTitle = "categoryTitle"
      }
    
    init() {}
    
    // MARK: Methods
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        eventId = try container.decode(String.self, forKey: .eventId)
        sessionId = try container.decodeIfPresent(String.self, forKey: 
       .sessionId) ?? ""
        title = try container.decodeIfPresent(String.self, forKey: .title) 
         ?? ""
        iconMarker = try container.decodeIfPresent(String.self, forKey: 
      .iconMarker) ?? ""
        isPaid = try container.decodeIfPresent(Bool.self, forKey: .isPaid) 
        ?? false
        startDT = try container.decodeIfPresent(String.self, forKey: 
      .startDT) ?? ""
        endDT = try container.decodeIfPresent(String.self, forKey: .endDT) 
      ?? ""
        subTitle = try container.decodeIfPresent(String.self, forKey: 
    .subTitle) ?? ""
        startDate = try container.decodeIfPresent(String.self, forKey: 
    .startDate) ?? ""
        endDate = try container.decodeIfPresent(String.self, forKey: 
     .endDate) ?? ""
        openTime = try container.decodeIfPresent(String.self, forKey: 
     .openTime) ?? ""
        closeTime = try container.decodeIfPresent(String.self, forKey: 
    .closeTime) ?? ""
        thumbnail = try container.decodeIfPresent(String.self, forKey: 
     .thumbnail) ?? ""
        locations = try container.decodeIfPresent([EventLocation].self, 
     forKey: .locations) ?? []
        categoryTitle = try container.decodeIfPresent(String.self, forKey: 
     .categoryTitle) ?? ""
        
       
        if let tempPrice = try container.decode([Price]?.self, forKey: 
     .prices) {
            var uniquePrices: [Price] = []
            for price in tempPrice {
                if !uniquePrices.contains(where: { (checkPrice) -> Bool in
                        checkPrice.priceInfo == price.priceInfo &&
                            checkPrice.value == price.value &&
                            checkPrice.currencyCode == price.currencyCode
                    }),
                    price.priceInfo.count > 0 &&
                        price.value.count > 0 &&
                        price.currencyCode.count > 0 &&
                        price.bookingUrl.count > 0 {
                    
                    // Filter for 0 value prices
                    if let priceValue = Double(price.value), priceValue > 0 
      {
                        uniquePrices.append(price)
                    }
                }
            }
            prices = uniquePrices
        }
        
        isSelected = BookMarkManager.shared.isFavoriteItem(by: eventId)
     }
     } 