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"
}
さて、ここに私の質問があります:
person
インスタンスをシリアル化して、JSONに変換される辞書にクラスのすべてのプロパティを手動で追加することなく、上記の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);
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プロトコルに準拠する必要があることに注意してください。
alternativeは JSONCodable であり、これは Swagger's コードジェネレーターによって使用されます。
そのために EVReflection を使用できます。次のようなコードを使用できます。
var person:Person = Person(json:jsonString)
または
var jsonString:String = person.toJsonString()
より詳細なサンプルコードについては、GitHubページを参照してください。 EVObjectをデータオブジェクトの基本クラスにするだけです。マッピングは必要ありません(jsonキーがプロパティ名と同じである限り)
Update:Swift 4はCodableをサポートしており、EVReflectionと同じくらい簡単ですが、パフォーマンスが向上しています。上記のような簡単な請負業者を使用したい場合は、この拡張機能を使用できます: Stuff/Codable
Swift 4)では、クラスをCodable
(Encodable
および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"
*/
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データをオブジェクトに変換するときに、辞書が返されることを期待し、マッピングプロセスを逆にします。しかし、もっと簡単な方法があるかもしれません。
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)
まず、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:
また、それらのライブラリを見てください
NSKeyValueCoding.h、特にsetValuesForKeysWithDictionary
を見てください。 jsonをNSDictionary
にデシリアライズすると、その辞書インスタンスを使用してオブジェクトを作成および初期化できます。オブジェクトに値を手動で設定する必要はありません。これにより、デシリアライゼーションがjsonでどのように機能するかがわかりますが、デシリアライゼーションプロセスをさらに制御する必要があることがすぐにわかります。これがNSObject
にカテゴリを実装する理由です。これにより、json逆シリアル化中に辞書で完全に制御されるNSObject
初期化が可能になり、基本的にオブジェクトをsetValuesForKeysWithDictionary
よりもさらに豊かにします。また、jsonデシリアライザーで使用されるプロトコルもあります。これにより、オブジェクトのデシリアライズを行って特定の側面を制御できます。たとえば、オブジェクトのNSArrayをデシリアライズする場合、オブジェクトに配列に格納されているオブジェクトの型名を尋ねます。