Home > database >  How to make an object from a Dynamic dictionary swift
How to make an object from a Dynamic dictionary swift

Time:02-17

This is my json:

"latest_receipt_info" =     (
            {
        "expires_date" = "2022-02-15 07:33:27 Etc/GMT";
        "is_in_intro_offer_period" = false;
        "is_trial_period" = false;
        "product_id" = "com.apollo66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
        "transaction_id" = 1000000968989231;
        "web_order_line_item_id" = 1000000072680194;
    },
            {
        "expires_date" = "2022-02-15 07:33:27 Etc/GMT";
        "is_in_intro_offer_period" = false;
        "is_trial_period" = false;
        "product_id" = "com.apollo66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
        "transaction_id" = 1000000968989231;
        "web_order_line_item_id" = 1000000072680194;
        "cancellation_date" = "2019-12-05 19:14:48 Etc/GMT",
    }
);

As you can see there are 1 extra attributes in the 1st dictionary. Now I want to make an object for this kind of dictionary where sometimes "cancellation_date": "***" attribute could appear and sometimes not. How can I do it?

This is my object:

struct LatestReceiptInfo {
    var expiresDate: Date? = nil
    let isInIntroOfferPeriod: Bool
    let isTrialPeriod: Bool
    let productId : String
    var cancellationDate: Date? = nil
}

And this is how I'm trying to bind the values:

for receiptInf in receiptInfo {
    let recInf = receiptInf as! NSDictionary
    guard let expiresDate = recInf["expires_date"] as? Date,
          let isInIntroOfferPeriod = recInf["is_in_intro_offer_period"] as? Bool,
          let isTrialPeriod = recInf["is_trial_period"] as? Bool,
          let productId = recInf["product_id"] as? String else {
              print("Something is not well")
              continue
          }
    let latestReceiptInfo = LatestReceiptInfo(expiresDate: expiresDate, isInIntroOfferPeriod: isInIntroOfferPeriod, isTrialPeriod: isTrialPeriod, productId: productId, cancellationDate: nil)
    latestReceiptInfoArray.append(latestReceiptInfo)
}

But it's not working. Thanks!

CodePudding user response:

Here is an example with notes

1- Any json should be surrounded with {} or [] and yours isn't

2- You have an invalid json

 "product_id" = "com.com.ARenewable6"; // = should be : and ; should be ,

3- You make a bool a string with "false" while it should be false

4- For supporting properties without _ you need to set keyDecodingStrategy to .convertFromSnakeCase and

5- For supporting string dates you need to assign a formatter to dateDecodingStrategy

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let str = """
{
"latest_receipt_info": [
{
    "expires_date": "2019-12-10 17:37:05 Etc/GMT",
    "is_in_intro_offer_period": false,
    "is_trial_period": false,
    "product_id":"com.com.ARenewable6",
    "cancellation_date": "2019-12-05 19:14:48 Etc/GMT"
}
]}

"""
        
        do  {
            
          //  let data = try JSONSerialization.data(withJSONObject: receiptInfo, options: [:])
            
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let form = DateFormatter()
            form.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
            decoder.dateDecodingStrategy = .formatted(form)
            let res = try decoder.decode([String:[LatestReceiptInfo]].self, from: Data(str.utf8))
            
            print(res)
        }
        catch {
            
            print(error)
        }
        
        
        
        
    }


}



struct LatestReceiptInfo: Codable {
    var expiresDate: Date? = nil
    let isInIntroOfferPeriod: Bool
    let isTrialPeriod: Bool
    let productId : String
    var cancellationDate: Date? = nil
}

CodePudding user response:

I have made stack.json file and add it to our project file by dragging it to file project

{
  "latest_receipt_info": [
    {
      "expires_date": "2019-12-10 17:37:05 Etc/GMT",
      "is_in_intro_offer_period": false,
      "is_trial_period": false,
      "product_id": "com.com.ARenewable6",
      "cancellation_date": "2019-12-05 19:14:48 Etc/GMT"
    },
    {
      "expires_date": "2019-12-10 17:37:05 Etc/GMT",
      "is_in_intro_offer_period": false,
      "is_trial_period": false,
      "product_id": "com.com.ARenewable6"
    }
  ]
}

for simplicity, I m naming variable as the same described in the JSON, though you can choose your own name for your modal class

struct JSONModal : Codable {
    var latest_receipt_info : [LatestReceiptInfo]
}

struct LatestReceiptInfo: Codable {
    var expires_date: Date? = nil
    let is_in_intro_offer_period: Bool
    let is_trial_period: Bool
    let product_id : String
    var cancellation_date: Date? = nil
}

1-> now first we want to load this json file from our project in real life project you will load it from web or some API call

    guard let jsonUrl = Bundle.main.url(forResource: "stack", withExtension: "json") else {
        fatalError("sorry this file doesnt exist")
    }
    guard let data = try? Data(contentsOf: jsonUrl) else {
        fatalError("json url may be currupted I m unable to produce Data out of url")
    }

at this point, you have a Data object with JSON store in it its time to decode it

let jsonDecoder = JSONDecoder()
    
    let form = DateFormatter()
    form.dateFormat = "yyyy-MM-dd HH:mm:ss VV" //thanks sh_khan for this
    jsonDecoder.dateDecodingStrategy = .formatted(form)

    guard let json = try? jsonDecoder.decode(JSONModal.self, from: data) else {
        fatalError("sorry unable to get json from given data may happen the model yiu have creatd have some problem")
    }

now when decode will not find any data like in our case one of the entries doesn't have a cancellation date then it will give nil

so we have our JSON lets print it

print("json is \(json)")
  • Related