programing

Swift 개체를 JSON으로 직렬화 또는 변환하려면 어떻게 해야 합니까?

codeshow 2023. 3. 8. 21:37
반응형

Swift 개체를 JSON으로 직렬화 또는 변환하려면 어떻게 해야 합니까?

이것은 클래스 이하입니다.

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

변환해야 할 필요가 있다

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

변수를 사전으로 설정하고 사전을 반환하는 함수에 개체를 수동으로 전달해 보았습니다.하지만 나는 이것을 성취할 더 나은 방법을 원할 것이다.

Swift 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)

Swift 4(Foundation)와 함께 오브젝트에 대한 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)!)

모든 세부사항 및 예는 여기에서 찾을있습니다. Swift 4를 사용한 JSON 파싱의 Ultimate Guide to JSON Parsing With JSwift 4

갱신: CodableSwift 4에서 도입된 프로토콜은 대부분의 경우에 충분합니다.JSON파싱 케이스아래 답변은 이전 버전의 Swift를 사용하고 있는 기존 사용자용입니다.

EVReflection:

  • 이것은 반사 원리의 작용이다.이 기능은 코드 소요가 적고,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)

오브젝트 맵퍼:

  • 다른 방법은 Object Mapper를 사용하는 것입니다.이를 통해 더 많은 제어가 가능하지만 더 많은 코드가 필요합니다.

예:

    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)

저는 상속이 필요 없는 작은 솔루션을 개발했습니다.하지만 그것은 많이 테스트되지 않았다.꽤 못생긴 현금인출기네요

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"]}}

이것은 완벽한 자동 해결책은 아니지만, 나는 이것이 관용적이고 자연스러운 방법이라고 생각한다.이렇게 하면 도서관 같은 것이 필요 없습니다.

다음과 같은 프로토콜을 만듭니다.

/// 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)

위의 답변 중 일부는 완전히 괜찮지만, 저는 단지 훨씬 더 읽기 쉽고 사용하기 쉽도록 여기에 확장을 추가했습니다.

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"
}

lib/framework가 존재하는지 여부는 확실하지 않지만 자동으로 실행하고 수동 작업을 피하고 싶은 경우:-)를 계속 사용합니다.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데모...

추추로 있습니다. 기기있있있있다다U아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 하다NSManagedObject 다 수 거예요.NSManagedObject대상 오브젝트에 이 할 필요가 .모든 서브클래스/관리 오브젝트에 이 기능을 구현할 필요가 없습니다.

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

이제 당신의 대상을 이렇게 만드세요.

사용자 = 사용자("1", pawan") 허용

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{
   
 }

2021 | SWIFT 5.1 | 결과 솔루션

입력 데이터:

struct ConfigCreds: Codable {
    // some params
}

사용방법:

// get JSON from Object
configCreds
   .asJson()
   .onSuccess{ varToSaveJson = $0 }
   .onFailure{ _ in // any failure code }

// get object of type "ConfigCreds" from JSON
someJsonString
    .decodeFromJson(type: ConfigCreds.self)
    .onSuccess { configCreds = $0 }
    .onFailure{ _ in // any failure code }

백코드:

@available(macOS 10.15, *)
public extension Encodable {
    func asJson() -> Result<String, Error>{
        JSONEncoder()
            .try(self)
            .flatMap{ $0.asString() }
    }
}

public extension String {
    func decodeFromJson<T>(type: T.Type) -> Result<T, Error> where T: Decodable {
        self.asData()
            .flatMap { JSONDecoder().try(type, from: $0) }
    }
}

///////////////////////////////
/// HELPERS
//////////////////////////////

@available(macOS 10.15, *)
fileprivate extension JSONEncoder {
    func `try`<T : Encodable>(_ value: T) -> Result<Output, Error> {
        do {
            return .success(try self.encode(value))
        } catch {
            return .failure(error)
        }
    }
}

fileprivate extension JSONDecoder {
    func `try`<T: Decodable>(_ t: T.Type, from data: Data) -> Result<T,Error> {
        do {
            return .success(try self.decode(t, from: data))
        } catch {
            return .failure(error)
        }
    }
}

fileprivate extension String {
    func asData() -> Result<Data, Error> {
        if let data = self.data(using: .utf8) {
            return .success(data)
        } else {
            return .failure(WTF("can't convert string to data: \(self)"))
        }
    }
}

fileprivate extension Data {
    func asString() -> Result<String, Error> {
        if let str = String(data: self, encoding: .utf8) {
            return .success(str)
        } else {
            return .failure(WTF("can't convert Data to string"))
        }
    }
}

fileprivate func WTF(_ msg: String, code: Int = 0) -> Error {
    NSError(code: code, message: msg)
}

언급URL : https://stackoverflow.com/questions/29599005/how-to-serialize-or-convert-swift-objects-to-json

반응형