json কীগুলি দিয়ে সুইফট 4 ডিকোডেবল যা ডিকোডিংয়ের সময় পর্যন্ত জানা যায় না




swift4 decodable (3)

খুব, এই প্রশ্ন জিজ্ঞাসা। অবশেষে এই জসনের জন্য কী উঠে এসেছে তা এখানে:

let json = """
{
    "BTC_BCN":{
        "last":"0.00000057",
        "percentChange":"0.03636363",
        "baseVolume":"47.08463318"
    },
    "BTC_BELA":{
        "last":"0.00001281",
        "percentChange":"0.07376362",
        "baseVolume":"5.46595029"
    }
}
""".data(using: .utf8)!

আমরা যেমন একটি কাঠামো তৈরি:

struct Pair {
    let name: String
    let details: Details

    struct Details: Codable {
        let last, percentChange, baseVolume: String
    }
}

এর পরে ডিকোড:

if let pairsDictionary = try? JSONDecoder().decode([String: Pair.Details].self, from: json) {

    var pairs: [Pair] = []
    for (name, details) in pairsDictionary {
        let pair = Pair(name: name, details: details)
        pairs.append(pair)
    }

    print(pairs)
}

পেয়ার.ডেটেলস.বেসভলিউম নয়, পেয়ার.বেসভলিউম কল করাও সম্ভব:

struct Pair {
    ......
    var baseVolume: String { return details.baseVolume }
    ......

অথবা কাস্টম init লিখুন:

struct Pair {
    .....
    let baseVolume: String
    init(name: String, details: Details) {
         self.baseVolume = details.baseVolume
    ......

সুইফট 4 ডিকোডেবল প্রোটোকল কী কী এমন কী ব্যবহার করে এমন একটি অভিধানকে মোকাবেলা করবে যার নাম রানটাইম পর্যন্ত জানা যায় না? উদাহরণ স্বরূপ:

  [
    {
      "categoryName": "Trending",
      "Trending": [
        {
          "category": "Trending",
          "trailerPrice": "",
          "isFavourit": null,
          "isWatchlist": null
        }
      ]
    },
    {
      "categoryName": "Comedy",
      "Comedy": [
        {
          "category": "Comedy",
          "trailerPrice": "",
          "isFavourit": null,
          "isWatchlist": null
        }
      ]
    }
  ]

এখানে আমাদের অভিধানের একটি অ্যারে রয়েছে; প্রথমটির কীগুলি categoryName এবং Trending , Trending কী এবং categoryName এবং ComedycategoryName নাম কীটির মানটি আমাকে দ্বিতীয় কীটির নাম বলে। আমি কীভাবে ডিকোডেবল ব্যবহার করে তা প্রকাশ করব?


কীভাবে আপনি CodingKeys সম্পত্তিটি সংজ্ঞায়িত করেন তার মধ্যে কীটি রয়েছে। যদিও এটি সাধারণভাবে একটি CodingKey তবে CodingKey প্রোটোকলের সাথে CodingKey এমন কোনও কিছু হতে পারে। এবং গতিশীল কীগুলি তৈরি করতে, আপনি একটি স্থির ফাংশন কল করতে পারেন:

struct Category: Decodable {
    struct Detail: Decodable {
        var category: String
        var trailerPrice: String
        var isFavorite: Bool?
        var isWatchlist: Bool?
    }

    var name: String
    var detail: Detail

    private struct CodingKeys: CodingKey {
        var intValue: Int?
        var stringValue: String

        init?(intValue: Int) { self.intValue = intValue; self.stringValue = "\(intValue)" }
        init?(stringValue: String) { self.stringValue = stringValue }

        static let name = CodingKeys.make(key: "categoryName")
        static func make(key: String) -> CodingKeys {
            return CodingKeys(stringValue: key)!
        }
    }

    init(from coder: Decoder) throws {
        let container = try coder.container(keyedBy: CodingKeys.self)
        self.name = try container.decode(String.self, forKey: .name)
        self.detail = try container.decode([Detail].self, forKey: .make(key: name)).first!
    }
}

ব্যবহার:

let jsonData = """
  [
    {
      "categoryName": "Trending",
      "Trending": [
        {
          "category": "Trending",
          "trailerPrice": "",
          "isFavourite": null,
          "isWatchlist": null
        }
      ]
    },
    {
      "categoryName": "Comedy",
      "Comedy": [
        {
          "category": "Comedy",
          "trailerPrice": "",
          "isFavourite": null,
          "isWatchlist": null
        }
      ]
    }
  ]
""".data(using: .utf8)!

let categories = try! JSONDecoder().decode([Category].self, from: jsonData)

(আমি isFavourit তে isFavourit পরিবর্তন isFavourit যেহেতু আমি ভেবেছিলাম এটি একটি ভুল বানান। যদি কোডটি না হয় তবে কোডটি মানিয়ে নেওয়া যথেষ্ট সহজ)


আপনি একটি কাস্টম স্ট্রাক লিখতে পারেন যা কোডিংকিজ অবজেক্ট হিসাবে কাজ করে এবং একটি স্ট্রিং দিয়ে এটি আরম্ভ করতে পারে যা এটি আপনার নির্দিষ্ট করা কীটি বের করে:

private struct CK : CodingKey {
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
    }
    var intValue: Int?
    init?(intValue: Int) {
        return nil
    }
}

সুতরাং, একবার আপনি পছন্দসই কী কী তা জানতে পারলে আপনি বলতে পারেন ( init(from:) ওভাররাইড করুন:

let key = // whatever the key name turns out to be
let con2 = try! decoder.container(keyedBy: CK.self)
self.unknown = try! con2.decode([Inner].self, forKey: CK(stringValue:key)!)

সুতরাং আমি যা করে শেষ করেছি তা ডিকোডার থেকে দুটি পাত্রে তৈরি করা হচ্ছে - একটি "categoryName" কীটির মান বের করার জন্য স্ট্যান্ডার্ড কোডিংকি এনাম ব্যবহার করে, এবং অন্যটি সদ্য কীটির নামটি সন্ধান করে তার কীটির মান বের করার জন্য সি কে স্ট্রাক্ট ব্যবহার করে:

init(from decoder: Decoder) throws {
    let con = try! decoder.container(keyedBy: CodingKeys.self)
    self.categoryName = try! con.decode(String.self, forKey:.categoryName)
    let key = self.categoryName
    let con2 = try! decoder.container(keyedBy: CK.self)
    self.unknown = try! con2.decode([Inner].self, forKey: CK(stringValue:key)!)
}

এখানে, তবে আমার সম্পূর্ণ ডিকোডেবল স্ট্রাক্ট:

struct ResponseData : Codable {
    let categoryName : String
    let unknown : [Inner]
    struct Inner : Codable {
        let category : String
        let trailerPrice : String
        let isFavourit : String?
        let isWatchList : String?
    }
    private enum CodingKeys : String, CodingKey {
        case categoryName
    }
    private struct CK : CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int?
        init?(intValue: Int) {
            return nil
        }
    }
    init(from decoder: Decoder) throws {
        let con = try! decoder.container(keyedBy: CodingKeys.self)
        self.categoryName = try! con.decode(String.self, forKey:.categoryName)
        let key = self.categoryName
        let con2 = try! decoder.container(keyedBy: CK.self)
        self.unknown = try! con2.decode([Inner].self, forKey: CK(stringValue:key)!)
    }
}

এবং এখানে পরীক্ষার বিছানা:

    let json = """
      [
        {
          "categoryName": "Trending",
          "Trending": [
            {
              "category": "Trending",
              "trailerPrice": "",
              "isFavourit": null,
              "isWatchlist": null
            }
          ]
        },
        {
          "categoryName": "Comedy",
          "Comedy": [
            {
              "category": "Comedy",
              "trailerPrice": "",
              "isFavourit": null,
              "isWatchlist": null
            }
          ]
        }
      ]
    """
    let myjson = try! JSONDecoder().decode(
        [ResponseData].self, 
        from: json.data(using: .utf8)!)
    print(myjson)

এবং মুদ্রণ বিবৃতিটির আউটপুট এখানে দেওয়া আছে, তা প্রমাণ করে যে আমরা আমাদের স্ট্রাক্টগুলি সঠিকভাবে জনপৃষ্ঠ করেছি:

[JustPlaying.ResponseData(
    categoryName: "Trending", 
    unknown: [JustPlaying.ResponseData.Inner(
        category: "Trending", 
        trailerPrice: "", 
        isFavourit: nil, 
        isWatchList: nil)]), 
 JustPlaying.ResponseData(
    categoryName: "Comedy", 
    unknown: [JustPlaying.ResponseData.Inner(
        category: "Comedy", 
        trailerPrice: "", 
        isFavourit: nil, 
        isWatchList: nil)])
]

অবশ্যই বাস্তব জীবনে আমরা কিছু ত্রুটি-পরিচালনা করতে চাই, সন্দেহ নেই!

পরে সম্পাদনা করুন আমি বুঝতে পেরেছি (অংশবিশেষে কোডডিফারেন্সের উত্তরের জন্য ধন্যবাদ) যে আমার দুটি পাত্রে দরকার নেই; আমি কোডিংকি এনামকে সরিয়ে দিতে পারি, এবং আমার সিকে স্ট্রাক্ট সমস্ত কাজ করতে পারে! এটি একটি সাধারণ উদ্দেশ্যে মূল নির্মাতা:

init(from decoder: Decoder) throws {
    let con = try! decoder.container(keyedBy: CK.self)
    self.categoryName = try! con.decode(String.self, forKey:CK(stringValue:"categoryName")!)
    let key = self.categoryName
    self.unknown = try! con.decode([Inner].self, forKey: CK(stringValue:key)!)
}




decodable