Swift Language
JSONの読み書き
サーチ…
構文
- NSJSONSerialization.JSONObjectWithData(jsonData、options:NSJSONReadingOptions)// jsonDataからオブジェクトを返します。このメソッドは失敗時にスローされます。
- NSJSONSerialization.dataWithJSONObject(jsonObject、options:NSJSONWritingOptions)// JSONオブジェクトからNSDataを返します。 NSJSONWritingOptions.PrettyPrintedに、より読みやすい出力オプションを渡してください。
Apple FoundationとSwift標準ライブラリを使用したJSONシリアライズ、エンコーディング、デコード
JSONSerializationクラスは、AppleのFoundationフレームワークに組み込まれています。
JSONを読む
JSONObjectWithData
機能がかかるNSData
、と返しAnyObject
。あなたはas?
結果をあなたの予想されるタイプに変換します。
do {
guard let jsonData = "[\"Hello\", \"JSON\"]".dataUsingEncoding(NSUTF8StringEncoding) else {
fatalError("couldn't encode string as UTF-8")
}
// Convert JSON from NSData to AnyObject
let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
// Try to convert AnyObject to array of strings
if let stringArray = jsonObject as? [String] {
print("Got array of strings: \(stringArray.joinWithSeparator(", "))")
}
} catch {
print("error reading JSON: \(error)")
}
options: []
代わりにoptions: .AllowFragments
を渡すことで、トップレベルのオブジェクトが配列や辞書でないときにJSONを読み取ることができます。
JSONを書く
dataWithJSONObject
呼び出すと、JSON互換のオブジェクト(ネストされた配列または文字列、数値、 NSNull
持つ辞書)がUTF-8としてエンコードされた生のNSData
されます。
do {
// Convert object to JSON as NSData
let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: [])
print("JSON data: \(jsonData)")
// Convert NSData to String
let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
print("JSON string: \(jsonString)")
} catch {
print("error writing JSON: \(error)")
}
options: .PrettyPrinted
を渡すことができoptions: .PrettyPrinted
代わりにoptions: .PrettyPrinted
options: []
、かわいい印刷用。
Swift 3でも同じ構文ですが、構文が異なります。
do {
guard let jsonData = "[\"Hello\", \"JSON\"]".data(using: String.Encoding.utf8) else {
fatalError("couldn't encode string as UTF-8")
}
// Convert JSON from NSData to AnyObject
let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
// Try to convert AnyObject to array of strings
if let stringArray = jsonObject as? [String] {
print("Got array of strings: \(stringArray.joined(separator: ", "))")
}
} catch {
print("error reading JSON: \(error)")
}
do {
// Convert object to JSON as NSData
let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
print("JSON data: \(jsonData)")
// Convert NSData to String
let jsonString = String(data: jsonData, encoding: .utf8)!
print("JSON string: \(jsonString)")
} catch {
print("error writing JSON: \(error)")
}
注:以下は、現在Swift 4.0以降でのみ利用可能です。
Swift 4.0以降、Swift標準ライブラリには、データのエンコードとデコードに対する標準化されたアプローチを定義するためのプロトコルEncodable
とDecodable
が含まれています。これらのプロトコルを採用することで、 Encoder
およびDecoder
プロトコルの実装でデータを取得し、JSONなどの外部表現との間でエンコードまたはデコードすることができます。適合Codable
プロトコルは両方兼ね備えEncodable
とDecodable
プロトコルを。これは、プログラムでJSONを処理するための推奨手段です。
自動的にエンコードとデコード
型コーディング可能なコードを作成する最も簡単な方法は、そのプロパティを既にCodable
可能な型として宣言することCodable
。これらの型には、 String
、 Int
、 Double
などの標準ライブラリ型が含まれます。およびDate
、 Data
、 URL
などの基盤型がありURL
。型のプロパティがコード化可能な場合、型自体は単に型を宣言するだけで自動的にCodable
に適合します。
Book
構造がCodable
準拠している次の例を考えてみましょう。
struct Book: Codable {
let title: String
let authors: [String]
let publicationDate: Date
}
Array
やDictionary
などの標準的なコレクションは、コード可能な型を含む場合、Codable
準拠していることに注意してください。
採用することによりCodable
、 Book
構造は今にエンコードすることができ、アップル財団クラス使用してJSONからデコードJSONEncoder
とJSONDecoder
にもかかわらず、 Book
自体は特にJSONを処理するための何のコードが含まれていません。カスタムエンコーダおよびデコーダは、それぞれ、 Encoder
およびDecoder
プロトコルに準拠して記述することもできる。
JSONデータにエンコードする
// Create an instance of Book called book
let encoder = JSONEncoder()
let data = try! encoder.encode(book) // Do not use try! in production code
print(data)
読みやすいように
encoder.outputFormatting = .prettyPrinted
を設定します。 ## JSONデータからのデコード
JSONデータからのデコード
// Retrieve JSON string from some source
let jsonData = jsonString.data(encoding: .utf8)!
let decoder = JSONDecoder()
let book = try! decoder.decode(Book.self, for: jsonData) // Do not use try! in production code
print(book)
上記の例では、
Book.self
はJSONをデコードする型をデコーダに通知します。
エンコードまたはデコード専用
場合によっては、APIからJSONデータのみを読み込む必要がある場合や、プログラムがJSONデータをAPIに送信する場合など、データをエンコード可能とデコード可能にする必要はありません。
JSONデータのみを書きたい場合は、タイプをEncodable
合わせます。
struct Book: Encodable {
let title: String
let authors: [String]
let publicationDate: Date
}
JSONデータの読み取りのみを目的とする場合は、タイプをDecodable
ます。
struct Book: Decodable {
let title: String
let authors: [String]
let publicationDate: Date
}
カスタムキー名の使用
APIは、スネークケースのようなSwift標準のラクダケース以外の命名規則を頻繁に使用します。デフォルトでJSONキーは型のプロパティ名と正確に一致する必要があるので、これはJSONのデコードに関しては問題になる可能性があります。これらのシナリオを処理するには、 CodingKey
プロトコルを使用してCodingKey
タイプのカスタムキーを作成します。
struct Book: Codable {
// ...
enum CodingKeys: String, CodingKey {
case title
case authors
case publicationDate = "publication_date"
}
}
CodingKeys
プロトコルを採用するタイプのCodingKeys
が自動的に生成されますが、上記の例で独自の実装を作成することで、デコーダがローカルCodable
ケースのpublicationDate
をAPIによって配信されたsnakeケースのpublication_date
に一致させることができます。
SwiftyJSON
SwiftyJSONは、通常のJSONシリアル化でのオプションの連鎖の必要性を取り除くために構築されたSwiftフレームワークです。
ここからダウンロードできます: https : //github.com/SwiftyJSON/SwiftyJSON
SwiftyJSONを使用しないと、コードはJSONオブジェクトの最初の本の名前を見つけるために次のようになります。
if let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]],
let bookName = (jsonObject[0]["book"] as? [String: AnyObject])?["name"] as? String {
//We can now use the book name
}
SwiftyJSONでは、これは非常に簡単です:
let json = JSON(data: data)
if let bookName = json[0]["book"]["name"].string {
//We can now use the book name
}
それらが無効な場合はnilを返すので、すべてのフィールドをチェックする必要はありません。
SwiftyJSONを使用するには、Gitリポジトリから適切なバージョンをダウンロードします。Swift 3のブランチがあります。 "SwiftyJSON.swift"をプロジェクトにドラッグしてクラスにインポートするだけです:
import SwiftyJSON
次の2つのイニシャライザを使用してJSONオブジェクトを作成できます。
let jsonObject = JSON(data: dataObject)
または
let jsonObject = JSON(jsonObject) //This could be a string in a JSON format for example
データにアクセスするには、下付き文字を使用します。
let firstObjectInAnArray = jsonObject[0]
let nameOfFirstObject = jsonObject[0]["name"]
次に、値を特定のデータ型に解析して、オプションの値を返します。
let nameOfFirstObject = jsonObject[0]["name"].string //This will return the name as a string
let nameOfFirstObject = jsonObject[0]["name"].double //This will return null
また、パスを迅速な配列にコンパイルすることもできます。
let convolutedPath = jsonObject[0]["name"][2]["lastName"]["firstLetter"].string
同じです:
let convolutedPath = jsonObject[0, "name", 2, "lastName", "firstLetter"].string
SwiftyJSONには、独自のエラーを出力する機能もあります。
if let name = json[1337].string {
//You can use the value - it is valid
} else {
print(json[1337].error) // "Array[1337] is out of bounds" - You cant use the value
}
JSONオブジェクトに書き込む必要がある場合は、添字を再度使用できます。
var originalJSON:JSON = ["name": "Jack", "age": 18]
originalJSON["age"] = 25 //This changes the age to 25
originalJSON["surname"] = "Smith" //This creates a new field called "surname" and adds the value to it
JSONの元のStringが必要な場合(たとえば、ファイルに書き込む必要がある場合など)は、そのままの値を取得できます。
if let string = json.rawString() { //This is a String object
//Write the string to a file if you like
}
if let data = json.rawData() { //This is an NSData object
//Send the data to your server if you like
}
フレディ
FreddyはBig Nerd Ranchが管理するJSON解析ライブラリです。それは3つの主な利点があります:
型の安全性:実行時のクラッシュを防止する方法でJSONを送受信する作業に役立ちます。
イディオム:複雑な文書や魔法のカスタム演算子なしで、Swiftのジェネリック、列挙、および機能的な機能を利用します。
エラー処理:一般的に発生するJSONエラーに関する有益なエラー情報を提供します。
JSONデータの例
これらの例で使用するJSONデータの例をいくつか定義しましょう。
{ "success": true, "people": [ { "name": "Matt Mathias", "age": 32, "spouse": true }, { "name": "Sergeant Pepper", "age": 25, "spouse": false } ], "jobs": [ "teacher", "judge" ], "states": { "Georgia": [ 30301, 30302, 30303 ], "Wisconsin": [ 53000, 53001 ] } }
let jsonString = "{\"success\": true, \"people\": [{\"name\": \"Matt Mathias\",\"age\": 32,\"spouse\": true},{\"name\": \"Sergeant Pepper\",\"age\": 25,\"spouse\": false}],\"jobs\": [\"teacher\",\"judge\"],\"states\": {\"Georgia\": [30301,30302,30303],\"Wisconsin\": [53000,53001]}}" let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
生データのデシリアライズ
データをデシリアライズするには、 JSON
オブジェクトを初期化して特定のキーにアクセスします。
do { let json = try JSON(data: jsonData) let success = try json.bool("success") } catch { // do something with the error }
我々はtry
アクセスするので、ここでjson
キーに"success"
それが存在しないか、または値がブール値ではないかもしれない-失敗する可能性があります。
また、JSON構造体にネストされた要素にアクセスするためのパスを指定することもできます。パスは、関心のある値へのパスを記述するキーとインデックスのコンマ区切りのリストです。
do { let json = try JSON(data: jsonData) let georgiaZipCodes = try json.array("states", "Georgia") let firstPersonName = try json.string("people", 0, "name") } catch { // do something with the error }
直接モデルの逆シリアル化
JSONは、 JSONDecodable
プロトコルを実装するモデルクラスに直接解析できます。
public struct Person { public let name: String public let age: Int public let spouse: Bool } extension Person: JSONDecodable { public init(json: JSON) throws { name = try json.string("name") age = try json.int("age") spouse = try json.bool("spouse") } } do { let json = try JSON(data: jsonData) let people = try json.arrayOf("people", type: Person.self) } catch { // do something with the error }
生データのシリアル化
どのJSON
値もNSData
直接シリアル化できます。
let success = JSON.Bool(false) let data: NSData = try success.serialize()
直接モデルのシリアライズ
実装するすべてのモデルクラスJSONEncodable
プロトコルは、直接シリアライズすることができNSData
。
extension Person: JSONEncodable { public func toJSON() -> JSON { return .Dictionary([ "name": .String(name), "age": .Int(age), "spouse": .Bool(spouse) ]) } } let newPerson = Person(name: "Glenn", age: 23, spouse: true) let data: NSData = try newPerson.toJSON().serialize()
矢印
Arrowは、Swiftの洗練されたJSON解析ライブラリです。
JSONを解析して、 <--
演算子の助けを借りてカスタムモデルクラスにマップすることができます:
identifier <-- json["id"]
name <-- json["name"]
stats <-- json["stats"]
例:
スウィフトモデル
struct Profile {
var identifier = 0
var name = ""
var link: NSURL?
var weekday: WeekDay = .Monday
var stats = Stats()
var phoneNumbers = [PhoneNumber]()
}
JSONファイル
{
"id": 15678,
"name": "John Doe",
"link": "https://apple.com/steve",
"weekdayInt" : 3,
"stats": {
"numberOfFriends": 163,
"numberOfFans": 10987
},
"phoneNumbers": [{
"label": "house",
"number": "9809876545"
}, {
"label": "cell",
"number": "0908070656"
}, {
"label": "work",
"number": "0916570656"
}]
}
マッピング
extension Profile: ArrowParsable {
mutating func deserialize(json: JSON) {
identifier <-- json["id"]
link <-- json["link"]
name <-- json["name"]
weekday <-- json["weekdayInt"]
stats <- json["stats"]
phoneNumbers <-- json["phoneNumbers"]
}
}
使用法
let profile = Profile()
profile.deserialize(json)
インストール:
カーセージ
github "s4cha/Arrow"
ココアポッド
pod 'Arrow'
use_frameworks!
手動で
あなたのXcodeプロジェクトにArrow.swiftをコピー&ペーストするだけです
https://github.com/s4cha/Arrow
フレームワークとして
GitHubリポジトリからArrowをダウンロードし、サンプルプロジェクトでFrameworkターゲットをビルドします 。次に、このフレームワークとリンクします。
カスタムオブジェクトへの単純なJSON解析
サードパーティ製のライブラリが良好であっても、JSONをパースするための簡単な方法は、あなたがオブジェクト持っているあなたが想像できるプロトコルによって提供されTodo
などを
struct Todo {
let comment: String
}
JSONを受け取るたびに、 NSJSONSerialization
オブジェクトを使用して、他の例に示すようにプレーンなNSData
を処理できます。
その後、単純なプロトコルJSONDecodable
を使用して
typealias JSONDictionary = [String:AnyObject]
protocol JSONDecodable {
associatedtype Element
static func from(json json: JSONDictionary) -> Element?
}
そして、あなたのTodo
構造体をJSONDecodable
準拠さJSONDecodable
ことがトリックになります
extension Todo: JSONDecodable {
static func from(json json: JSONDictionary) -> Todo? {
guard let comment = json["comment"] as? String else { return nil }
return Todo(comment: comment)
}
}
あなたはこのjsonコードで試すことができます:
{
"todos": [
{
"comment" : "The todo comment"
}
]
}
APIから取得した場合は、前の例のようにAnyObject
インスタンスにAnyObject
ます。その後、インスタンスがJSONDictionary
インスタンスかどうかを確認できます
guard let jsonDictionary = dictionary as? JSONDictionary else { return }
JSONにTodo
配列があるため、このケースに固有のチェックするもう1つの点は、 todos
辞書です
guard let todosDictionary = jsonDictionary["todos"] as? [JSONDictionary] else { return }
これで、辞書の配列が得られたので、 flatMap
を使ってTodo
オブジェクトのそれぞれを変換することができます(配列からnil
値が自動的に削除されます)
let todos: [Todo] = todosDictionary.flatMap { Todo.from(json: $0) }
JSON解析スウィフト3
ここで使用するJSONファイルはanimals.json
{
"Sea Animals": [
{
"name": "Fish",
"question": "How many species of fish are there?" },
{
"name": "Sharks",
"question": "How long do sharks live?"
},
{
"name": "Squid",
"question": "Do squids have brains?"
},
{
"name": "Octopus",
"question": "How big do octopus get?"
},
{
"name": "Star Fish",
"question": "How long do star fish live?"
}
],
"mammals": [
{
"name": "Dog",
"question": "How long do dogs live?"
},
{
"name": "Elephant",
"question": "How much do baby elephants weigh?"
},
{
"name": "Cats",
"question": "Do cats really have 9 lives?"
},
{
"name": "Tigers",
"question": "Where do tigers live?"
},
{
"name": "Pandas",
"question": "WHat do pandas eat?"
} ] }
プロジェクトでJSONファイルをインポートする
この単純な関数を実行すると、JSONファイルを出力できます
func jsonParsingMethod() {
//get the file
let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
let content = try! String(contentsOfFile: filePath!)
let data: Data = content.data(using: String.Encoding.utf8)!
let json: NSDictionary = try! JSONSerialization.jsonObject(with: data as Data, options:.mutableContainers) as! NSDictionary
//Call which part of the file you'd like to pare
if let results = json["mammals"] as? [[String: AnyObject]] {
for res in results {
//this will print out the names of the mammals from out file.
if let rates = res["name"] as? String {
print(rates)
}
}
}
}
テーブルビューに配置したい場合は、まずNSObjectを使って辞書を作成します。
ParsingObject
というParsingObject
新しいファイルを作成し、文字列変数を作成します。
変数名がJSONファイルと同じであることを確認してください
。たとえば、私たちのプロジェクトではname
とquestion
がありquestion
ので、新しい素早いファイルでは、
var name: String?
var question: String?
ViewController.swiftに戻したNSObjectを初期化します。var array = ParsingObjectその後、マイナーな変更を加えて以前と同じメソッドを実行します。
func jsonParsingMethod() {
//get the file
let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
let content = try! String(contentsOfFile: filePath!)
let data: Data = content.data(using: String.Encoding.utf8)!
let json: NSDictionary = try! JSONSerialization.jsonObject(with: data as Data, options:.mutableContainers) as! NSDictionary
//This time let's get Sea Animals
let results = json["Sea Animals"] as? [[String: AnyObject]]
//Get all the stuff using a for-loop
for i in 0 ..< results!.count {
//get the value
let dict = results?[i]
let resultsArray = ParsingObject()
//append the value to our NSObject file
resultsArray.setValuesForKeys(dict!)
array.append(resultsArray)
}
}
次に、これを行うことでテーブルビューに表示します。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//This is where our values are stored
let object = array[indexPath.row]
cell.textLabel?.text = object.name
cell.detailTextLabel?.text = object.question
return cell
}