JSON के लिए स्विफ़्ट ऑब्जेक्ट्स को क्रमांकित या रूपांतरित कैसे करें?


84

यह नीचे की कक्षा

class User: NSManagedObject {
  @NSManaged var id: Int
  @NSManaged var name: String
}

में परिवर्तित करने की आवश्यकता है

{
    "id" : 98,
    "name" : "Jon Doe"
}

मैंने मैन्युअल रूप से एक फ़ंक्शन को ऑब्जेक्ट पास करने की कोशिश की, जो चर को शब्दकोश में सेट करता है और शब्दकोश को वापस करता है। लेकिन मैं इसे पूरा करने के लिए एक बेहतर तरीका चाहता हूं।


1
आपका सबसे अच्छा दांव इसके माध्यम से चलना है और इसे सरणियों और डीकट्स पर सहेजना है, फिर कनवर्ट करें।
योजनाबद्ध


@ शेमेट्रिक क्या आप मुझे एक उदाहरण के लिए बता सकते हैं? मैं नहीं जानता कि कैसे एक वस्तु के माध्यम से चलाने के लिए।
पंकज सुरेश

ठीक है, आपको ऑब्जेक्ट के माध्यम से स्वयं जाने की जरूरत है, सभी मान लें, और इसे मैन्युअल रूप से एक तानाशाही में जोड़ें, और दोहराएं।
योजनाबद्ध

@ रसायन विज्ञान मैंने वास्तव में कोशिश की है। लेकिन बड़ी वस्तुओं के लिए संकलन समय नाटकीय रूप से बढ़ता है।
पंकज सुरेश

जवाबों:


130

स्विफ्ट 4 में, आप Codableटाइप से विरासत में ले सकते हैं ।

struct Dog: Codable {
    var name: String
    var owner: String
}

// Encode
let dog = Dog(name: "Rex", owner: "Etgar")

let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(dog)
let json = String(data: jsonData, encoding: String.Encoding.utf16)

// Decode
let jsonDecoder = JSONDecoder()
let secondDog = try jsonDecoder.decode(Dog.self, from: jsonData)

26
एन्कोडिंग प्रकार .utf16 के बजाय .utf8 होना चाहिए
जिंग होंग

2
@ChanJingHong यह इस बात पर निर्भर करता है कि आप क्या सांकेतिक शब्दों में बदलना चाहते हैं
Etgar

इस विशिष्ट उदाहरण के लिए .utf16 काम करता है? मैंने कोशिश की, लेकिन यह काम नहीं करता है।
जिंग होंग

@ChanJingHong स्ट्रेंज, मैंने 3 महीने पहले इसकी कोशिश की और यह काम कर गया। मुझे लगता है कि मुझे डिकोडिंग विधि में एक तर्क के रूप में एन्कोडिंग प्रकार भी रखना चाहिए था। मैं इसे देख लूँगा।
Etgar

2
प्रश्न विशेष रूप से एन्कोडिंग class(मुझे क्या चाहिए) के बारे में नहीं था struct
गोंडो

39

स्विफ्ट 4 (फाउंडेशन) के साथ अब यह मूल रूप से दोनों तरह से समर्थित है, JSON स्ट्रिंग किसी ऑब्जेक्ट पर - JSON स्ट्रिंग के लिए ऑब्जेक्ट। कृपया यहां JSONDecoder () और यहां JSONEncoder () का Apple दस्तावेज़ देखें

JSON स्ट्रिंग टू ऑब्जेक्ट

let jsonData = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
let myStruct = try! decoder.decode(myStruct.self, from: jsonData)

JSONString को स्विफ्ट ऑब्जेक्ट

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try! encoder.encode(myStruct)
print(String(data: data, encoding: .utf8)!)

आप सभी विवरण और उदाहरण यहां जान सकते हैं अंतिम गाइड JSON Parsing With Swift 4 के साथ


25

अद्यतन: Codable स्विफ्ट 4 में प्रस्तुत प्रोटोकॉल JSONपार्सिंग के अधिकांश मामलों के लिए पर्याप्त होना चाहिए । नीचे उत्तर उन लोगों के लिए है जो स्विफ्ट के पिछले संस्करणों में फंस गए हैं और विरासत कारणों से हैं

मूल्यांकन :

  • यह प्रतिबिंब सिद्धांत का काम करता है। यह कम कोड लेता है और यह भी समर्थन करता है NSDictionary, NSCoding, Printable, HashableऔरEquatable

उदाहरण:

    class User: EVObject { # extend EVObject method for the class
       var id: Int = 0
       var name: String = ""
       var friends: [User]? = []
    }

    # use like below
    let json:String = "{\"id\": 24, \"name\": \"Bob Jefferson\", \"friends\": [{\"id\": 29, \"name\": \"Jen Jackson\"}]}"
    let user = User(json: json)

ऑब्जेक्टमैपर :

  • एक अन्य तरीका ObjectMapper का उपयोग करके है। यह अधिक नियंत्रण देता है, लेकिन बहुत अधिक कोड भी लेता है।

उदाहरण:

    class User: Mappable { # extend Mappable method for the class
       var id: Int?
       var name: String?

       required init?(_ map: Map) {

       }

       func mapping(map: Map) { # write mapping code
          name    <- map["name"]
          id      <- map["id"]
       }

    }

    # use like below
    let json:String = "{\"id\": 24, \"name\": \"Bob Jefferson\", \"friends\": [{\"id\": 29, \"name\": \"Jen Jackson\"}]}"
    let user = Mapper<User>().map(json)

क्या यह मानचित्रण छवियों का भी समर्थन करता है ??
चार्ली

1
@Charlie माफ करना मुझे यकीन नहीं है अगर यह संभव है।
लिंग सुरेश

1
@ सुरेश: जैसा कि दिखाए गए उदाहरणों के अनुसार कस्टम परिवर्तन लिखना संभव है। मैंने छवि को स्ट्रिंग में परिवर्तित किया और फिर Json ऑब्जेक्ट में जोड़ा। यह बहुत विशेष रूप से घड़ी ओएस के साथ काम करने में मदद करता है
चार्ली

1
नमस्ते, क्या आप जानते हैं कि मैप्पेबल क्लास को इनिशियलाइज़ करना और प्रॉपर्टीज़ को मैन्युअल रूप से सेट करना और फिर ऑब्जेक्ट को jsonString में बदलना है?
VAAA

स्विफ्ट 4 / ios 11 से कोड करने योग्य प्रोटोकॉल का प्रभाव क्या है ?? । क्या हम इसका उपयोग करते हुए NSSONagedObject को JSON को स्विफ्ट 4 में बदल सकते हैं ??
user1828845

13

मैंने एक छोटे से समाधान पर थोड़ा काम किया जिसमें विरासत की आवश्यकता नहीं है। लेकिन इसका ज्यादा परीक्षण नहीं किया गया है। यह बहुत बदसूरत एटीएम है।

https://github.com/peheje/JsonSerializerSwift

आप इसे परीक्षण करने के लिए एक खेल के मैदान में पास कर सकते हैं। जैसे कक्षा संरचना निम्नलिखित:

//Test nonsense data
class Nutrient {
    var name = "VitaminD"
    var amountUg = 4.2

    var intArray = [1, 5, 9]
    var stringArray = ["nutrients", "are", "important"]
}

class Fruit {
    var name: String = "Apple"
    var color: String? = nil
    var weight: Double = 2.1
    var diameter: Float = 4.3
    var radius: Double? = nil
    var isDelicious: Bool = true
    var isRound: Bool? = nil
    var nullString: String? = nil
    var date = NSDate()

    var optionalIntArray: Array<Int?> = [1, 5, 3, 4, nil, 6]
    var doubleArray: Array<Double?> = [nil, 2.2, 3.3, 4.4]
    var stringArray: Array<String> = ["one", "two", "three", "four"]
    var optionalArray: Array<Int> = [2, 4, 1]

    var nutrient = Nutrient()
}

var fruit = Fruit()
var json = JSONSerializer.toJson(fruit)

print(json)

प्रिंट

{"name": "Apple", "color": null, "weight": 2.1, "diameter": 4.3, "radius": null, "isDelicious": true, "isRound": null, "nullString": null, "date": "2015-06-19 22:39:20 +0000", "optionalIntArray": [1, 5, 3, 4, null, 6], "doubleArray": [null, 2.2, 3.3, 4.4], "stringArray": ["one", "two", "three", "four"], "optionalArray": [2, 4, 1], "nutrient": {"name": "VitaminD", "amountUg": 4.2, "intArray": [1, 5, 9], "stringArray": ["nutrients", "are", "important"]}}

क्या आप कृपया इसका स्विफ्ट 2.3 संस्करण प्रदान कर सकते हैं?
एच रावल

8

यह एक सही / स्वचालित समाधान नहीं है, लेकिन मेरा मानना ​​है कि यह ऐसा करने के लिए मुहावरेदार और देशी तरीका है। इस तरह से आपको किसी भी पुस्तकालयों या इस तरह की आवश्यकता नहीं है।

एक प्रोटोकॉल बनाएं जैसे:

/// A generic protocol for creating objects which can be converted to JSON
protocol JSONSerializable {
    private var dict: [String: Any] { get }
}

extension JSONSerializable {
    /// Converts a JSONSerializable conforming class to a JSON object.
    func json() rethrows -> Data {
        try JSONSerialization.data(withJSONObject: self.dict, options: nil)
    }
}

फिर इसे अपनी कक्षा में लागू करें जैसे:

class User: JSONSerializable {
    var id: Int
    var name: String

    var dict { return ["id": self.id, "name": self.name]  }
}

अभी:

let user = User(...)
let json = user.json()

नोट: यदि आप jsonएक स्ट्रिंग के रूप में चाहते हैं , तो एक स्ट्रिंग में बदलना बहुत आसान है:String(data: json, encoding .utf8)


6

उपरोक्त कुछ उत्तर पूरी तरह से ठीक हैं, लेकिन मैंने यहां एक विस्तार जोड़ा, बस इसे और अधिक पठनीय और प्रयोग करने योग्य बनाने के लिए।

extension Encodable {
    var convertToString: String? {
        let jsonEncoder = JSONEncoder()
        jsonEncoder.outputFormatting = .prettyPrinted
        do {
            let jsonData = try jsonEncoder.encode(self)
            return String(data: jsonData, encoding: .utf8)
        } catch {
            return nil
        }
    }
}

struct User: Codable {
     var id: Int
     var name: String
}

let user = User(id: 1, name: "name")
print(user.convertToString!)

// यह निम्नलिखित की तरह प्रिंट करेगा:

{
  "id" : 1,
  "name" : "name"
}

2

यह निश्चित नहीं है कि यदि लिब / फ्रेमवर्क मौजूद है, लेकिन यदि आप इसे स्वचालित रूप से करना चाहते हैं और आप मैन्युअल श्रम से बचना चाहते हैं तो MirrorType...

class U {

  var id: Int
  var name: String

  init(id: Int, name: String) {
    self.id = id
    self.name = name
  }

}

extension U {

  func JSONDictionary() -> Dictionary<String, Any> {
    var dict = Dictionary<String, Any>()

    let mirror = reflect(self)

    var i: Int
    for i = 0 ; i < mirror.count ; i++ {
      let (childName, childMirror) = mirror[i]

      // Just an example how to check type
      if childMirror.valueType is String.Type {
        dict[childName] = childMirror.value
      } else if childMirror.valueType is Int.Type {
        // Convert to NSNumber for example
        dict[childName] = childMirror.value
      }
    }

    return dict
  }

}

इसे एक मोटे उदाहरण के रूप में लें, उचित रूपांतरण समर्थन की कमी, पुनरावृत्ति का अभाव है, ... यह सिर्फ MirrorTypeप्रदर्शन है ...

PS यहाँ यह किया गया है U, लेकिन आप बढ़ाने जा रहे हैं NSManagedObjectऔर फिर आप सभी NSManagedObjectउपवर्गों को परिवर्तित करने में सक्षम होंगे । सभी उपवर्गों / प्रबंधित वस्तुओं में इसे लागू करने की आवश्यकता नहीं है।


नमस्ते, मैं इस विधि की कोशिश कर रहा हूं, लेकिन हर बार मुझे गिनती के रूप में 0 मिल रहा है। क्या आप अधिक विशिष्ट हो सकते हैं जैसे मुझे क्या करना चाहिए? मुझे लगता है कि @ मनमुटाव समस्या पैदा कर रहा है। मैं NSManagedObject को कैसे बढ़ाऊं?
पंकज सुरेश

के साथ कोशिश नहीं की @NSManaged। शायद यह आपकी समस्या का कारण बन रहा है। इस मामले में, मैं इसे ऑब्जेक्टिव-सी में लिखूंगा और फिर स्विफ्ट से इसका इस्तेमाल करूंगा।
zrzka

0

2020 | स्विफ्ट 5.1:

(SWIFT 4 के साथ भी काम करता है)


समाधान के लिए तैयार!

उपयोग:

var msgTemplates = [msgTemlate]()

// load from file
msgTemplates = try! Serializer.load(from: url)!

// save to file
Serializer.save(data: msgTemplates, to: url)

निम्नलिखित कोड 3 चीजों को हल करता है:

  • फ़ाइल को सहेजने के लिए 1 स्ट्रिंग
  • फ़ाइल लोड करने के लिए 1 स्ट्रिंग
  • कुछ कोडेबल तत्व के JSON को प्राप्त / प्रिंट करने की क्षमता element.toJsonString
    import Foundation

    public class Serializer{
        static func save<T>(data: T, to url: URL) where T : Encodable{
            guard let json = data.toJsonString else { return }

            do {
                try json.write(to: url, atomically: true, encoding: String.Encoding.utf8)
            }
            catch { /* error handling here */ }
        }

        static func load<T>(from url: URL) throws -> T? where T : Decodable {
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601 // for human-read date format

            guard let dataStr = try? String(contentsOf: url, encoding: String.Encoding.utf8 ),
                  let data = dataStr.data(using: String.Encoding.utf8 ),
                  let result = try? decoder.decode( T.self , from: data)
            else { return nil }

            return result
        }
    }

    extension Encodable {
        var toJsonString: String? {
            let encoder = JSONEncoder()
            encoder.outputFormatting = .prettyPrinted  // nice formatted for reading by human
            encoder.dateEncodingStrategy = .iso8601    // for human-read date format

            do {
                let jsonData = try encoder.encode(self)
                return String(data: jsonData, encoding: .utf8)
            } catch {
                return nil
            }
        }
    }

पुनश्च: और टो डेटा कोडेबल होना चाहिए:

struct msgTemlate: Codable { 
     //some params
}

PS2: msgTemlate के पास एनम हैं, वे भी कोडेबल होने चाहिए


0
struct User:Codable{
 var id:String?
 var name:String?
 init(_ id:String,_ name:String){
   self.id  = id
   self.name = name
 }
}

अब बस अपनी वस्तु को इस तरह बनाओ

उपयोगकर्ता दें = उपयोगकर्ता ("1", "पावन")

do{
      let userJson =  try JSONEncoder().encode(parentMessage) 
            
    }catch{
         fatalError("Unable To Convert in Json")      
    }

फिर json से ऑब्जेक्ट पर पुन: कनेक्ट करें

let jsonDecoder = JSONDecoder()
do{
   let convertedUser = try jsonDecoder.decode(User.self, from: userJson.data(using: .utf8)!)
 }catch{
   
 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.