web-dev-qa-db-ja.com

Swiftでのオブジェクトの自動JSONシリアライゼーションおよびデシリアライゼーション

Swiftでクラスインスタンスを自動的にシリアル化および逆シリアル化する方法を探しています。次のクラスを定義したとしましょう…

class Person {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

…およびPersonインスタンス:

let person = Person(firstName: "John", lastName: "Doe")

personのJSON表現は次のようになります。

{
    "firstName": "John",
    "lastName": "Doe"
}

さて、ここに私の質問があります:

  1. personインスタンスをシリアル化して、JSONに変換される辞書にクラスのすべてのプロパティを手動で追加することなく、上記のJSONを取得するにはどうすればよいですか?
  2. 上記のJSONを逆シリアル化し、Person型に静的に型指定されたインスタンス化されたオブジェクトを取得するにはどうすればよいですか?繰り返しますが、プロパティを手動でマップする必要はありません。

Json.NET を使用してC#でこれを行う方法は次のとおりです。

var person = new Person("John", "Doe");
string json = JsonConvert.SerializeObject(person);
// {"firstName":"John","lastName":"Doe"}

Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json);
38
Marius Schulz

WWDC2017 @ 24:48(Swift 4)に示されているように、Codableプロトコルを使用できます。例

public struct Person : Codable {
   public let firstName:String
   public let lastName:String
   public let location:Location
}

シリアル化するには

let payload: Data = try JSONEncoder().encode(person)

デシリアライズするには

let anotherPerson = try JSONDecoder().decode(Person.self, from: payload)

すべてのプロパティはCodableプロトコルに準拠する必要があることに注意してください。

alternativeJSONCodable であり、これは Swagger's コードジェネレーターによって使用されます。

26
Alex Nolasco

そのために EVReflection を使用できます。次のようなコードを使用できます。

var person:Person = Person(json:jsonString)

または

var jsonString:String = person.toJsonString()

より詳細なサンプルコードについては、GitHubページを参照してください。 EVObjectをデータオブジェクトの基本クラスにするだけです。マッピングは必要ありません(jsonキーがプロパティ名と同じである限り)

Update:Swift 4はCodableをサポートしており、EVReflectionと同じくらい簡単ですが、パフォーマンスが向上しています。上記のような簡単な請負業者を使用したい場合は、この拡張機能を使用できます: Stuff/Codable

20
Edwin Vermeer

Swift 4)では、クラスをCodableEncodableおよびDecodableプロトコル)に準拠させるだけで、 JSONのシリアル化と逆シリアル化を実行します。

import Foundation

class Person: Codable {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

使用方法#1(PersonインスタンスをJSON文字列にエンコードします):

let person = Person(firstName: "John", lastName: "Doe")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // if necessary
let data = try! encoder.encode(person)
let jsonString = String(data: data, encoding: .utf8)!
print(jsonString)

/*
 prints:
 {
   "firstName" : "John",
   "lastName" : "Doe"
 }
 */

使用方法#2(JSON文字列をPersonインスタンスにデコード):

let jsonString = """
{
  "firstName" : "John",
  "lastName" : "Doe"
}
"""

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

/*
 prints:
 ▿ __lldb_expr_609.Person #0
   - firstName: "John"
   - lastName: "Doe"
 */
8
Imanou Petit

NSJSONSerializationとの間で変換を行うことができるJSONというFoundationクラスがあります。

JSONからオブジェクトに変換する方法は次のようになります。

let jsonObject = NSJSONSerialization.JSONObjectWithData(data, 
    options: NSJSONReadingOptions.MutableContainers, 
    error: &error) as NSDictionary

このメソッドの最初の引数はJSONデータですが、文字列オブジェクトとしてではなく、NSDataオブジェクトとしてです(これは、とにかくJSONデータを取得することが多い方法です)。

JSONデータを引数として受け取り、このメソッドを使用してクラスの初期化オブジェクトを返すクラスのファクトリメソッドが必要になる可能性が高いでしょう。

このプロセスを逆にして、オブジェクトからJSONデータを作成するには、dataWithJSONObjectを使用します。この場合、JSONに変換でき、NSData? 戻ってきた。繰り返しますが、おそらくクラスのインスタンスメソッドとして引数を必要としないヘルパーメソッドを作成する必要があります。


私が知る限り、これを処理する最も簡単な方法は、オブジェクトのプロパティをディクショナリにマップし、そのディクショナリを渡してオブジェクトをJSONデータに変換する方法を作成することです。次に、JSONデータをオブジェクトに変換するときに、辞書が返されることを期待し、マッピングプロセスを逆にします。しかし、もっと簡単な方法があるかもしれません。

5
nhgrif

ObjectMapper ライブラリを使用してこれを実現できます。これにより、変数名と値、および準備されたJSONをより詳細に制御できます。このライブラリを追加した後、Mappableクラスを拡張し、mapping(map: Map)関数を定義します。

例えば

   class User: Mappable {
       var id: Int?
       var name: String?

       required init?(_ map: Map) {

       }

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

    }

以下のように使用してください

   let user = Mapper<User>().map(JSONString)
4
Penkey Suresh

まず、Swiftこのようなオブジェクトを作成します

struct Person {
    var firstName: String?;
    var lastName: String?;
    init() {

    }
}

その後、組み込みのNSJSONSerializationを使用して取得したJSONデータをシリアル化し、値を解析しますPersonオブジェクトに.

var person = Person();
var error: NSError?;
var response: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(), error: &error);

if let personDictionary = response as? NSDictionary {
    person.firstName = personDictionary["firstName"] as? String;
    person.lastName = personDictionary["lastName"] as? String;
}

UPDATE:

また、それらのライブラリを見てください

Swift-JsonSerialiser

ROJSONParser

0
Eddy Liu

NSKeyValueCoding.h、特にsetValuesForKeysWithDictionaryを見てください。 jsonをNSDictionaryにデシリアライズすると、その辞書インスタンスを使用してオブジェクトを作成および初期化できます。オブジェクトに値を手動で設定する必要はありません。これにより、デシリアライゼーションがjsonでどのように機能するかがわかりますが、デシリアライゼーションプロセスをさらに制御する必要があることがすぐにわかります。これがNSObjectにカテゴリを実装する理由です。これにより、json逆シリアル化中に辞書で完全に制御されるNSObject初期化が可能になり、基本的にオブジェクトをsetValuesForKeysWithDictionaryよりもさらに豊かにします。また、jsonデシリアライザーで使用されるプロトコルもあります。これにより、オブジェクトのデシリアライズを行って特定の側面を制御できます。たとえば、オブジェクトのNSArrayをデシリアライズする場合、オブジェクトに配列に格納されているオブジェクトの型名を尋ねます。

0
simplatek