Swift

ファイルとJSON

FoundationによるUTF-8の保存・読み込みと、CodableでのJSON変換を学びます。

対象:Swift 6系。基礎はコンソールで学びます。iOSアプリの開発にはmacOSとXcodeが必要です。

01

保存先と実行方法

入門の構造体とエラー処理を使います。空の練習フォルダーでmain.swiftを作り、swift main.swift で実行してください。例は実行時の作業フォルダーへファイルを作成・上書きします。各コードは独立しており、全体を置き換えて使えます。

FoundationはファイルやJSONなどを扱うライブラリです。このページはコンソール用です。iOSアプリでは作業フォルダーを保存先にせず、アプリのDocumentsなど適切な領域を使います。

Windowsでは 入門のコンパイル手順と同じく、main.swiftを書き換えるたびにコンパイルして実行します。

02

UTF-8で保存して読む

import Foundation でライブラリを使います。作業フォルダーからURLを作り、UTF-8で文字列を保存します。atomically: true は一時ファイルを利用して置き換える指定です。

main.swift(全体を置き換え)SWIFT
import Foundation
let directory = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
let url = directory.appendingPathComponent("swift-memo.txt")
do {
    try "Swiftの学習メモ".write(to: url, atomically: true, encoding: .utf8)
    let text = try String(contentsOf: url, encoding: .utf8)
    print(text)
} catch {
    print("保存または読み込みに失敗しました")
}
実行結果OUTPUT
Swiftの学習メモ

同じ場所にswift-memo.txtができ、その中に表示と同じ文字列があることも確認してください。書き込み権限がない場所ではcatchへ進みます。

03

CodableでJSONを往復する

Codable に適合する構造体はJSONEncoderでData(バイト列)へ変換し、JSONDecoderで元の型に戻せます。型がJSONの構造と一致しないとデコードは失敗します。

main.swift(全体を置き換え)SWIFT
import Foundation
struct Memo: Codable {
    let title: String
    let minutes: Int
}
let directory = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
let url = directory.appendingPathComponent("swift-memo.json")
do {
    let original = Memo(title: "Optional", minutes: 20)
    let data = try JSONEncoder().encode(original)
    try data.write(to: url, options: .atomic)
    let saved = try Data(contentsOf: url)
    let memo = try JSONDecoder().decode(Memo.self, from: saved)
    print(memo.title)
    print(memo.minutes)
} catch {
    print("JSONを保存・読み込みできませんでした")
}
実行結果OUTPUT
Optional
20

作成されるJSONは {"title":"Optional","minutes":20} と同じ内容です。キーの並び順はこの例では固定していません。Memo.self は変換先の型自体を渡す書き方です。

04

壊れたデータを読む場合

実際に不正なJSONを渡し、アプリを停止させずに失敗を伝えられるか確認します。存在しないファイル、型の違う値、必須キーがない場合も成功扱いにしないことが大切です。

main.swift(全体を置き換え)SWIFT
import Foundation
struct Memo: Decodable { let minutes: Int }
let data = Data("{\"minutes\":\"二十\"}".utf8)
do {
    let memo = try JSONDecoder().decode(Memo.self, from: data)
    print(memo.minutes)
} catch {
    print("minutesには整数が必要です")
}
実行結果OUTPUT
minutesには整数が必要です
05

練習:複数のメモを保存

Memoの配列をswift-memos.jsonへ保存して読み戻し、合計学習時間を表示してください。10分と20分の2件なら30です。

解答例と結果を確認する

まず自分で書いてから、処理の順番と結果を比べましょう。

main.swift(全体を置き換え)SWIFT
import Foundation
struct Memo: Codable { let minutes: Int }
let directory = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
let url = directory.appendingPathComponent("swift-memos.json")
do {
    let memos = [Memo(minutes: 10), Memo(minutes: 20)]
    try JSONEncoder().encode(memos).write(to: url, options: .atomic)
    let data = try Data(contentsOf: url)
    let restored = try JSONDecoder().decode([Memo].self, from: data)
    var total = 0
    for memo in restored { total += memo.minutes }
    print(total)
} catch {
    print("メモを保存・読み込みできませんでした")
}
実行結果OUTPUT
30

公式ドキュメントで確認する:Foundation