Swiftでのデータ保存のたった12の方法

Swift言語を用いたデータ保存方法のイラストSwift
この記事は約25分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

私たちが日常で使用するアプリは、さまざまな情報を保存しています。

ユーザーの設定、ゲームのスコア、写真や動画など、それらの情報はアプリを閉じても維持され、再度開いた際にその状態が保持されています。

この背後には「データ保存」という技術があります。

●Swiftでのデータ保存とは?

SwiftはAppleが開発したプログラミング言語で、iOSやmacOSなどのアプリを開発する際に使用されます。

このSwiftを用いて、アプリ内でのデータの保存や取り出しを実現する方法がいくつかあります。

○データ保存の必要性

データを保存することで、アプリを再起動してもユーザーの情報や進捗を維持できます。

これにより、ユーザーはストレスなくアプリを使用できるようになります。

また、データの保存はオフライン時にもアプリが機能することを保証する重要な要素となっています。

○Swiftでの主な保存方法

Swiftでのデータ保存には様々な方法がありますが、主なものとして次の3つを挙げます。

  1. UserDefaults:シンプルなデータやユーザーの設定情報を保存するのに適しています。
  2. CoreData:複雑なデータ構造や大量のデータを効率的に管理するのに適しています。
  3. ファイルシステム:テキストや画像、動画などのファイルを直接保存するのに適しています。

このコードではUserDefaultsを使ってデータを保存するコードを表しています。

この例では文字列を保存して取り出しています。

// データの保存
let defaults = UserDefaults.standard
defaults.set("こんにちは", forKey: "greeting")

// データの取り出し
if let greeting = defaults.string(forKey: "greeting") {
    print(greeting)
}

このコードを実行すると、コンソールに「こんにちは」と表示されます。

ここでは、”こんにちは”という文字列を”greeting”というキーで保存して、その後、同じキーを使用してデータを取り出しています。

●UserDefaultsを使ったデータ保存

Swiftには複数のデータ保存の方法がありますが、まずは最も基本的で手軽なUserDefaultsを使った方法について説明します。

UserDefaultsは、アプリケーションの設定情報など、少量のデータを保存するのに適しています。

その名の通り、「ユーザーのデフォルト設定」を保存するためのものです。

○サンプルコード1:基本的な保存方法

このコードではUserDefaultsを使って、文字列のデータを保存する方法を表しています。

具体的には、「こんにちは」という文字列を”greeting”というキーで保存し、それを取り出して表示する操作を行います。

// UserDefaultsのインスタンスを取得
let defaults = UserDefaults.standard

// 文字列データの保存
defaults.set("こんにちは", forKey: "greeting")

// 保存したデータの取り出しと表示
if let greeting = defaults.string(forKey: "greeting") {
    print(greeting)
}

上記のコードを実行すると、コンソールに「こんにちは」と出力されます。

ここでは、まずUserDefaults.standardを使ってUserDefaultsのインスタンスを取得しています。

次に、setメソッドでデータを保存しています。

最後に、stringメソッドで保存したデータを取り出し、print関数で表示しています。

○サンプルコード2:データの読み出し

次に、異なる型のデータをUserDefaultsに保存し、それを読み出す方法を見てみましょう。

この例では、整数値と真偽値を保存し、それらを取り出す操作を行います。

// 整数値の保存
defaults.set(25, forKey: "age")

// 真偽値の保存
defaults.set(true, forKey: "isMember")

// 整数値の取り出し
let age = defaults.integer(forKey: "age")
print("年齢は\(age)歳です。")

// 真偽値の取り出し
let isMember = defaults.bool(forKey: "isMember")
print(isMember ? "会員です。" : "会員ではありません。")

上記のコードを実行すると、コンソールに「年齢は25歳です。」と「会員です。」と出力されます。

UserDefaultsは、文字列以外にも様々な基本的なデータ型をサポートしており、それぞれの型に合わせたメソッドを用いて保存や取り出しを行うことができます。

●CoreDataを使ったデータ保存

Swiftで複雑なデータ構造や大量のデータを効率的に保存する場合、CoreDataは非常に強力なフレームワークとなります。

CoreDataは、オブジェクトの永続化、リレーションシップ管理、バージョニングなど、データベース操作に関連する多くのタスクを容易に行うことができます。

○サンプルコード3:CoreDataのセットアップ

このコードでは、CoreDataの初期セットアップ方法を表しています。

具体的には、データモデルを利用して、マネージドオブジェクトコンテキストと持続的なストアコーディネーターを設定します。

import CoreData

// CoreDataスタックのセットアップ
class CoreDataStack {

    // マネージドオブジェクトモデル
    lazy var managedObjectModel: NSManagedObjectModel = {
        let modelURL = Bundle.main.url(forResource: "MyDataModel", withExtension: "momd")!
        return NSManagedObjectModel(contentsOf: modelURL)!
    }()

    // 持続的ストアコーディネーター
    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.appendingPathComponent("MyDataModel.sqlite")
        var failureReason = "データの保存や読み込みに失敗しました。"
        do {
            try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
        } catch {
            fatalError("\(failureReason): \(error)")
        }
        return coordinator
    }()

    // アプリケーションドキュメントディレクトリへのURL
    lazy var applicationDocumentsDirectory: URL = {
        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return urls[urls.count-1]
    }()
}

このコードを用いることで、データモデルMyDataModelに基づくCoreDataの環境がセットアップされます。

次に、この環境を利用してデータを追加・取得する方法を見ていきます。

○サンプルコード4:データの追加と取得

次に、先ほどセットアップしたCoreDataの環境を利用して、データの追加と取得を行う方法を紹介します。

// データの追加
let context = CoreDataStack().persistentStoreCoordinator.viewContext
let newEntity = NSEntityDescription.insertNewObject(forEntityName: "EntityName", into: context) as! MyEntity
newEntity.attributeName = "サンプルデータ"

do {
    try context.save()
} catch let error as NSError {
    print("保存に失敗しました。 \(error), \(error.userInfo)")
}

// データの取得
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "EntityName")
do {
    let results = try context.fetch(fetchRequest)
    for result in results as! [NSManagedObject] {
        print(result.value(forKey: "attributeName") as! String)
    }
} catch let error as NSError {
    print("データの取得に失敗しました。 \(error), \(error.userInfo)")
}

上記のコードでは、EntityNameというエンティティにデータを追加し、その後同じエンティティからデータを取得しています。

実際には、MyEntityEntityNameattributeNameといった名前を、実際のデータモデルの内容に合わせて変更する必要があります。

○サンプルコード5:データの更新と削除

最後に、データの更新と削除の方法を説明します。

この例では、特定の条件に一致するデータを検索し、そのデータを更新または削除します。

// データの更新
let fetchUpdate = NSFetchRequest<NSFetchRequestResult>(entityName: "EntityName")
fetchUpdate.predicate = NSPredicate(format: "attributeName = %@", "サンプルデータ")

do {
    let results = try context.fetch(fetchUpdate)
    let updateData = results[0] as! NSManagedObject
    updateData.setValue("更新されたデータ", forKey: "attributeName")
    try context.save()
} catch let error as NSError {
    print("データの更新に失敗しました。 \(error), \(error.userInfo)")
}

// データの削除
let fetchDelete = NSFetchRequest<NSFetchRequestResult>(entityName: "EntityName")
fetchDelete.predicate = NSPredicate(format: "attributeName = %@", "更新されたデータ")

do {
    let results = try context.fetch(fetchDelete)
    let deleteData = results[0] as! NSManagedObject
    context.delete(deleteData)
    try context.save()
} catch let error as NSError {
    print("データの削除に失敗しました。 \(error), \(error.userInfo)")
}

このコードを用いると、特定の条件に一致するデータを検索し、そのデータを更新または削除することができます。

●ファイルシステムを使ったデータ保存

Swiftのアプリケーションでは、ファイルシステムを使って簡単にテキストや画像といったデータを保存することができます。

特に大きなデータや簡易的な保存を求められる場面では、UserDefaultsやCoreDataよりもファイルシステムを使用した方が適切な場合があります。

○サンプルコード6:テキストファイルの保存と読み出し

このコードでは、テキストファイルを作成して保存し、後でそのテキストファイルを読み出す方法を表しています。

import Foundation

// テキストの保存
let text = "Swiftでのテキスト保存方法"
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = directoryURL.appendingPathComponent("sample.txt")
do {
    try text.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
    print("テキストの保存に失敗しました。")
}

// テキストの読み出し
do {
    let loadedText = try String(contentsOf: fileURL, encoding: .utf8)
    print(loadedText) // "Swiftでのテキスト保存方法"と表示されます。
} catch {
    print("テキストの読み出しに失敗しました。")
}

このサンプルコードにより、アプリケーションのドキュメントディレクトリにsample.txtというテキストファイルが作成され、その中に指定したテキストが保存されます。

そして、テキストファイルを読み込むことで、保存した内容を再び取得することができます。

○サンプルコード7:画像ファイルの保存と読み出し

次に、画像ファイルの保存と読み出し方法を紹介します。

import UIKit

// 画像の保存
if let image = UIImage(named: "sampleImage") {
    if let data = image.jpegData(compressionQuality: 1.0) {
        let filename = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("sampleImage.jpg")
        try? data.write(to: filename)
    }
}

// 画像の読み出し
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("sampleImage.jpg")
if let loadedData = try? Data(contentsOf: fileURL) {
    let loadedImage = UIImage(data: loadedData)
    // こちらでloadedImageをImageViewなどに表示することができます。
}

このコードを用いると、sampleImageという名前の画像ファイルをドキュメントディレクトリに保存し、後でその画像ファイルを読み出して再利用することができます。

画像の保存にはjpegDataメソッドを使用しており、保存する品質をcompressionQualityで指定することができます。

●Swiftでのデータ保存の応用例

Swiftでのデータ保存方法は多岐にわたりますが、日常的にアプリケーションで利用されるものから高度なものまでさまざまな応用例が考えられます。

ここでは、設定画面のデータ保存から、タスク管理アプリでのデータ保存までの例をいくつか挙げ、具体的な実装方法を詳細に説明していきます。

○サンプルコード8:設定画面のデータ保存

このコードでは、設定画面でユーザーが選択したテーマカラーや文字サイズなどの情報をUserDefaultsを使って保存する例を表しています。

import UIKit

let userDefaults = UserDefaults.standard

// 設定項目の保存
let themeColor = UIColor.blue
userDefaults.set(themeColor.cgColor.components, forKey: "themeColor")
let fontSize = 14
userDefaults.set(fontSize, forKey: "fontSize")

// 設定項目の読み出し
if let colorComponents = userDefaults.array(forKey: "themeColor") as? [CGFloat], colorComponents.count == 4 {
    let loadedColor = UIColor(red: colorComponents[0], green: colorComponents[1], blue: colorComponents[2], alpha: colorComponents[3])
    // こちらでloadedColorをアプリのテーマカラーとして適用することができます。
}
let loadedFontSize = userDefaults.integer(forKey: "fontSize")

このサンプルコードにより、設定画面でユーザーが選択したテーマカラーや文字サイズなどの情報が、UserDefaultsを通じて保存されます。

後にアプリを再起動した際も、これらの設定は維持されるため、ユーザーは自分の好みに合わせたカスタマイズを行うことができます。

○サンプルコード9:タスク管理アプリのデータ保存

次に、タスク管理アプリでのタスクの追加や削除時のデータ保存の方法を紹介します。

ここではCoreDataを利用して実装を行います。

import CoreData

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

// タスクの追加
let newTask = Task(context: context)
newTask.title = "Swiftの勉強"
newTask.detail = "プロトコルとデリゲートについて"
newTask.date = Date()

do {
    try context.save()
} catch {
    print("タスクの保存に失敗しました。")
}

// タスクの取得
let request: NSFetchRequest<Task> = Task.fetchRequest()
do {
    let tasks = try context.fetch(request)
    for task in tasks {
        print(task.title!) // "Swiftの勉強"と表示されます。
    }
} catch {
    print("タスクの読み出しに失敗しました。")
}

このコードを用いると、新しいタスクを追加し、その後で追加したタスクを読み出すことができます。

また、CoreDataを利用することで、アプリを再起動した際もタスクの情報は維持されるため、長期間にわたるタスク管理が可能となります。

○サンプルコード10:ゲームのスコア保存

ゲームアプリでは、ユーザーが達成したスコアを保存して、次回プレイ時にもその記録を維持することが一般的です。

ここでは、Swiftを用いてゲームのスコアを簡単に保存・取得する方法を解説します。

具体的には、UserDefaultsを活用した方法を紹介します。

このコードでは、ユーザーがゲームで獲得したスコアをUserDefaultsを使って保存し、アプリ起動時にそのスコアを取得するコードを表しています。

import UIKit

let userDefaults = UserDefaults.standard

// スコアの保存
let score: Int = 1200  // 仮のスコアとして1200を使用
userDefaults.set(score, forKey: "gameScore")

// スコアの読み出し
let loadedScore = userDefaults.integer(forKey: "gameScore")
print(loadedScore) // 1200と表示されます

このサンプルコードにより、ゲーム内で獲得したスコアがUserDefaultsによって保存されます。

そして、アプリを再起動した際や次回のプレイ時にも、スコアの情報は維持されるので、ユーザーは自分の最高スコアを確認しながらゲームを楽しむことができます。

ただし、UserDefaultsは軽量なデータの保存に適しています。

大量のゲームデータや複雑なデータ構造を持つ情報を保存する場合、CoreDataやファイルシステムを利用することを検討してください。

○サンプルコード11:アプリのテーマカラーの保存

多くのアプリでは、ユーザーの好みに合わせてテーマカラーや背景色を変更することができます。

ここでは、ユーザーが選択したテーマカラーを保存し、次回アプリ起動時にその色を適用する方法を解説します。

このコードでは、ユーザーが選択したテーマカラーをUserDefaultsを使って保存し、アプリ起動時にそのカラーを取得して適用する例を表しています。

import UIKit

let userDefaults = UserDefaults.standard

// テーマカラーの保存
let selectedColor = UIColor.red
userDefaults.set(selectedColor.cgColor.components, forKey: "themeColor")

// テーマカラーの読み出し
if let colorComponents = userDefaults.array(forKey: "themeColor") as? [CGFloat], colorComponents.count == 4 {
    let loadedColor = UIColor(red: colorComponents[0], green: colorComponents[1], blue: colorComponents[2], alpha: colorComponents[3])
    // こちらでloadedColorをアプリのテーマカラーとして適用します。
}

このコードを利用すれば、ユーザーが選択したテーマカラーを容易に保存し、再度アプリを起動したときにも前回選択したテーマカラーを維持することができます。

これにより、ユーザーエクスペリエンスが向上し、アプリの利用満足度も高まるでしょう。

●注意点と対処法

データ保存に関してSwiftを使用する際、いくつかの注意点とそれに対する対処法が存在します。

これらのポイントを理解し、正しい実装を心掛けることで、アプリケーションの安定性やユーザーエクスペリエンスを向上させることができます。

○型の違いによるエラー

Swiftは強く型付けされた言語であるため、異なるデータ型間での変換や代入が許容されません。

これが原因となって、データ保存時に型のエラーが発生することがあります。

このコードでは、Int型のデータをString型としてUserDefaultsに保存しようとする例を表しています。

この場合、型の違いによりエラーが発生します。

let userDefaults = UserDefaults.standard

let score: Int = 1200
userDefaults.set(score, forKey: "gameScoreString") // エラーが発生

対処法として、型変換を行い、正しい型として保存することが必要です。

下記のコードは、Int型のスコアをString型に変換して保存する方法を示しています。

let score: Int = 1200
let scoreString = String(score)
userDefaults.set(scoreString, forKey: "gameScoreString")

変換した結果、正しい型としてデータが保存されるため、エラーは発生しません。

○容量オーバーによるエラー

UserDefaultsは、軽量なデータを保存するための手段です。

大量のデータや大きなファイルを保存する場合、容量オーバーやパフォーマンスの低下の原因となる可能性があります。

対処法として、大量のデータや大きなファイルを保存する場合は、FileシステムやCoreDataなどのデータ保存方法を選択することが適切です。

これにより、データの保存・読み取りの速度を維持し、アプリケーションのパフォーマンスを保持することができます。

○バージョンアップ時のデータ移行

アプリケーションのバージョンアップを行う際、新しいデータ構造や保存方法に変更が生じることがあります。

この場合、既存のデータを新しい形式に移行する必要が生じます。

このコードでは、旧バージョンで保存されたデータを新しいバージョンの形式に変換する例を表しています。

// 旧バージョンでの保存方法
let userDefaults = UserDefaults.standard
let oldScore: Int = userDefaults.integer(forKey: "oldGameScore")

// 新しいバージョンへの移行
let newScoreFormat: [String: Any] = ["score": oldScore, "date": Date()]
userDefaults.set(newScoreFormat, forKey: "newGameScoreFormat")

この方法を用いることで、旧バージョンで保存されたデータを新しい形式に適切に変換し、新しいバージョンのアプリケーションでも利用することができます。

●カスタマイズ方法

Swiftでのデータ保存は、基本的な方法だけでなく、さまざまなカスタマイズや拡張が可能です。

ここでは、データ保存の更なる拡張方法や他のライブラリ、フレームワークの活用方法について詳しく解説します。

○データ保存の拡張と最適化

Swiftでのデータ保存をより効率的にするための方法として、データの圧縮やキャッシングの導入が考えられます。

このコードでは、Swift標準のJSONEncoderJSONDecoderを用いて、データをJSON形式で保存し、読み出す方法を表しています。

この例では、ユーザー情報をJSON形式で変換し、UserDefaultsに保存しています。

import Foundation

struct UserInfo {
    let name: String
    let age: Int
}

let userDefaults = UserDefaults.standard

let userInfo = UserInfo(name: "山田太郎", age: 30)
if let encodedData = try? JSONEncoder().encode(userInfo) {
    userDefaults.set(encodedData, forKey: "userInfo")
}

if let savedData = userDefaults.data(forKey: "userInfo") {
    let decodedUserInfo = try? JSONDecoder().decode(UserInfo.self, from: savedData)
    // decodedUserInfoには、保存したユーザー情報が入っています。
}

この方法を用いることで、データ構造を変えずに、簡単に情報の保存と取得が行えます。

また、JSON形式は他のプラットフォームとの互換性も高いため、異なるシステム間でのデータのやり取りも容易になります。

○他のライブラリやフレームワークの活用

Swiftのコミュニティは活発であり、多くの外部ライブラリやフレームワークが公開されています。

これらを活用することで、データの保存や管理をさらに強化することが可能です。

例として、Realmというデータベースフレームワークを挙げます。

Realmは、Swiftでの高速なデータベース操作をサポートしており、簡単なAPIでデータの保存や取得、更新が行えます。

このコードでは、Realmを使用してデータを保存し、取得する方法を表しています。

import RealmSwift

// データモデルの定義
class Person: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
}

// Realmのインスタンスを作成
let realm = try! Realm()

// データの保存
let person = Person()
person.name = "鈴木一郎"
person.age = 25
try! realm.write {
    realm.add(person)
}

// データの取得
let results = realm.objects(Person.self).filter("name == '鈴木一郎'")
for p in results {
    // pには、"鈴木一郎"という名前のPersonオブジェクトが入っています。
}

Realmを使用することで、複雑なクエリや大量のデータの取り扱いも、簡単かつ高速に行うことが可能になります。

また、Realmはマルチプラットフォーム対応であるため、iOSだけでなく、AndroidやWindowsなどの他のプラットフォームでの使用も考慮されています。

まとめ

Swiftでのデータ保存に関して、本記事を通じてさまざまな方法やテクニックを解説しました。

データ保存はアプリケーションの基本的な機能の一つであり、ユーザーの情報や設定、ゲームのスコアなど、様々なデータを持続的に保存し、再利用するための手段として不可欠です。

本記事では、UserDefaults、CoreData、ファイルシステムといった基本的な保存方法から、Realmなどの外部ライブラリやフレームワークの活用方法まで、幅広く解説しました。

それぞれの方法には独自の特徴や利点、注意点がありますので、アプリケーションの要件や目的に応じて適切な保存方法を選択することが大切です。

また、データ保存の際には、型の違いや容量オーバー、バージョンアップ時のデータ移行など、さまざまな問題が生じる可能性があります。

これらの問題を適切に対処し、ユーザーに安全かつ快適なアプリケーションを提供するための知識も習得することが重要です。

Swiftでのデータ保存の技術は日々進化しており、新しいライブラリやフレームワーク、技術が次々と登場しています。

技術の動向を常にチェックし、新しい知識を取り入れることで、より効率的で強力なデータ保存の実装を目指すことができるでしょう。

本記事がSwiftでのデータ保存を学ぶ皆さんの手助けとなり、より質の高いアプリケーション開発の手助けとなることを願っています。

データ保存の実装に取り組む際には、本記事の内容を参考にしながら、最適な方法を選び、実装に取り組むことをおすすめします。