6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Swift】RepositoryパターンでRealmを使ってみた - 個人開発事例あり -

Last updated at Posted at 2024-01-15

私のRealmの使用方法についてご紹介します。この記事では、Realmの基本的な定義と、個人開発での利用方法に焦点を当て、Repositoryパターンの実装について説明します。

今回は、こちらの個人開発で使用したRealmの定義とリポジトリーを切り出して説明します。もしよろしければ実際にアプリをダウンロードして使用してみてください。そして、星5をください🙇‍♂!!

では説明に進みます。

Repositoryパターンを用いる目的

Repositoryパターンを採用する主な目的は、データ管理するツールであるRealmが将来的にサービス終了する可能性がある場合、データを簡単に他のツール(例:CoreDataやSwiftData)に移行しやすくできます。もしRealmで定義したモデルクラスをViewControllerなどで直接使用している場合、ツールの変更に伴い、多くのコードを書き直す必要があります。しかし、Repositoryパターンを利用してRealmモデルを構造体に変換するRepositoryクラスを作成すれば、移行時に修正が必要なコードを最小限に抑えることができます。

モデル定義

以下に、実際のコードの例を挙げ、その説明を加えます。

CharacterRecognition 構造体

struct CharacterRecognition {
    var uuidString = UUID().uuidString
    var title: String
    var content: String
    var createdAt: Date = Date()
    var uuid: UUID? {
        UUID(uuidString: uuidString)
    }
}

RealmCharacterRecognition クラス

class RealmCharacterRecognition: Object {
    @Persisted(primaryKey: true)
    var uuidString = ""
    @Persisted
    var title: String
    @Persisted
    var content: String
    @Persisted
    var createdAt: Date
    var uuid: UUID? {
        UUID(uuidString: uuidString)
    }
    
    convenience init(title: String, text: String, createdAt: Date) {
        self.init()
        self.title = title
        self.content = text
        self.createdAt = createdAt
    }
}

CharacterRecognitionRealmCharacterRecognitionは、それぞれデータのモデル定義を行っています。RealmCharacterRecognitionはRealmでのデータ管理で用いており、ViewControllerなどで直接使用することは避けます。データを保存する際はRealmCharacterRecognitionに変換して保存し、ViewControllerで使用する際はCharacterRecognitionに変換して利用するように実装しました。

RealmCharacterRecognition ⇔ CharacterRecognition の変換

private extension CharacterRecognition {
    // RealmCharacterRecognitionからCharacterRecognitionへの変換
    init(managedObject: RealmCharacterRecognition) {
        self.uuidString = managedObject.uuidString
        self.title = managedObject.title
        self.content = managedObject.content
        self.createdAt = managedObject.createdAt
    }

    // CharacterRecognitionからRealmCharacterRecognitionへの変換
    func managedObject() -> RealmCharacterRecognition {
        let realmCharacterRecognition = RealmCharacterRecognition()
        realmCharacterRecognition.uuidString = self.uuidString
        realmCharacterRecognition.title = self.title
        realmCharacterRecognition.content = self.content
        realmCharacterRecognition.createdAt = self.createdAt
        return realmCharacterRecognition
    }
}

CharacterRecognition構造体とRealmCharacterRecognitionクラスの相互変換を行うための拡張です。以下の実装を行うことによって、RealmCharacterRecognitionCharacterRecognition の相互変換が楽に実装できます。

Repositoryクラスの作成

CharacterRecognitionRepository クラス

final class CharacterRecognitionRepository {
    private let realm = try! Realm()
    
    // 文字認識データの読み込み
    func loadCharacterRecognition(ascending: Bool) -> [CharacterRecognition] {
        // Realmから文字認識データを取得
        let realmCharacterRecognitions = realm
            .objects(RealmCharacterRecognition.self)
            .sorted(byKeyPath: "createdAt", ascending: ascending)
        
        // Realmオブジェクトを構造体に変換して配列に格納
        let realmCharacterRecognitionsArray = Array(realmCharacterRecognitions)
        let characterRecognitions = realmCharacterRecognitionsArray.map { CharacterRecognition(managedObject: $0) }
        
        return characterRecognitions
    }
    
    // 文字認識データの検索
    func loadCharacterRecognition(ascending: Bool, text: String) -> [CharacterRecognition] {
        // Realmから文字認識データを取得し、テキストでフィルタリング
        let realmCharacterRecognitions = realm
            .objects(RealmCharacterRecognition.self)
            .sorted(byKeyPath: "createdAt", ascending: ascending)
            .filter("content CONTAINS '\(text)' OR title CONTAINS '\(text)'")
        
        // Realmオブジェクトを構造体に変換して配列に格納
        let realmCharacterRecognitionsArray = Array(realmCharacterRecognitions)
        let characterRecognitions = realmCharacterRecognitionsArray.map { CharacterRecognition(managedObject: $0) }
        
        return characterRecognitions
    }
    
    // 文字認識データの追加
    func appendCharacterRecognition(characterRecognition: CharacterRecognition) {
        try! realm.write {
            let realmCharacterRecognition = characterRecognition.managedObject()
            realm.add(realmCharacterRecognition)
        }
    }
    
    // 文字認識データの更新
    func updateCharacterRecognition(characterRecognition: CharacterRecognition) {
        try! realm.write {
            let realmCharacterRecognition = realm.object(ofType: RealmCharacterRecognition.self, forPrimaryKey: characterRecognition.uuidString)
            realmCharacterRecognition?.title = characterRecognition.title
            realmCharacterRecognition?.content = characterRecognition.content
        }
    }

    // 文字認識データの削除
    func removeCharacterRecognition(characterRecognition: CharacterRecognition) {
        guard let countHistory = realm.object(
            ofType: RealmCharacterRecognition.self,
            forPrimaryKey: characterRecognition.uuidString
        ) else { return }
        
        // データを削除
        try! realm.write {
            realm.delete(countHistory)
        }
    }
}

このRepositoryクラスは、文字認識データの管理を行い、データの読み込み、検索、追加、更新、削除を行います。さらに、構造体とRealmモデルの相互変換もこのクラスで行います。

まとめ

この記事では、Realmの基本的な使い方と、Repositoryパターンを利用したデータ管理のアプローチについて説明しました。この方法を取り入れることで、将来的なデータストレージツールの変更にも柔軟に対応できるようになります。ぜひ参考にしてみてください。

余談

こちらの方法は、アプリ道場サロンというオンラインサロンのコードレビュー会という勉強会で教えていただきました。
iOSでのアプリ開発に興味のある方がぜひ!おすすめです!

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?