18
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Realmに初期データを入れてマスターとして使いたい

Last updated at Posted at 2017-04-25

・モチベーション
 Realmにあらかじめデータを投入した状態で使用したかった

・前提
 id, value程度の単純なモデル

##今回の成果物

こちらに置いてあります
negibouze/Realm-Register-Initial-Data

##1. プロジェクトにRealmを追加する

省略

##2. モデルを作成する

step1. 基底のクラスを作成する

DBBase.swift
import Foundation
import RealmSwift

/* 基底 */
class DBBase: Object {
    dynamic var id = 0
    dynamic var name = ""

    override static func primaryKey() -> String? {
        return "id"
    }

    override static func indexedProperties() -> [String] {
        return ["id"]
    }
}

step2. モデルを作成する

基本的なパターン

Prefecture.swift
import Foundation
import RealmSwift

/* 都道府県 */
class Prefecture: DBBase {
}

サブモデルを持っているパターン

Owner.swift
import Foundation
import RealmSwift

/* オーナー */
class Owner: DBBase {
    var dogs = List<Dog>()
}

##3. シード(データ)を作成する

step1. protocolを作成する

RealmSeed.swift
protocol RealmSeed {
    associatedtype SeedType: DBBase
    static var values: [[Any]] { get }
    static func items() -> [SeedType]
}

extension RealmSeed {
    static func items() -> [SeedType] {
        return values.map { val in
            let t = SeedType()
            t.id = val[0] as! Int
            t.name = val[1] as! String
            return t
        }
    }
}

step2. structを作成する

!この方法だとデータ数が5,000件くらいで結構つらいです。

PrefectureSeed.swift
struct PrefectureSeed: RealmSeed {
    typealias SeedType = Prefecture
    static var values: [[Any]] {
        return PrefectureData.data
    }
}

struct PrefectureData {
    static let data: [[Any]] = [
        [1, "北海道"],
        [2, "青森県"],
        [3, "岩手県"],
        [4, "宮城県"],
        中略
        [47, "沖縄県"]
    ]
}
OwnerSeed.swift
import RealmSwift

struct OwnerSeed: RealmSeed {
    typealias SeedType = Owner
    static var values: [[Any]] {
        return OwnerData.data
    }
}

extension OwnerSeed {
    static func items() -> [SeedType] {
        return values.map { val in
            let id = val[0] as! Int
            let t = SeedType()
            t.id = id
            t.name = val[1] as! String
            let l = { (_ ownerId: Int) -> [Dog] in
                let data = DogData.get(ownerId)
                return data.map { v in
                    let d = Dog()
                    d.id = v[0] as! Int
                    d.name = v[1] as! String
                    return d
                }
            }(id)
            t.dogs = List<Dog>(l)
            return t
        }
    }
}

struct OwnerData {
    static var data: [[Any]] {
        return [
            [1, "オーナー1"],
            [2, "オーナー2"],
            [3, "オーナー3"],
            [4, "オーナー4"],
            [5, "オーナー5"]
        ]
    }
}

struct DogData {
    static let data: [Int: [[Any]]] = [
        1: [
            [11, "オーナー1の犬1"],
            [12, "オーナー1の犬2"],
            [13, "オーナー1の犬3"],
            [14, "オーナー1の犬4"],
            [15, "オーナー1の犬5"]
        ],
        2: [
            [21, "オーナー2の犬1"],
            [22, "オーナー2の犬2"],
            [23, "オーナー2の犬3"]
        ]
        以下略
    ]
    
    static func get(_ ownerId: Int) -> [[Any]] {
        return data[ownerId]!
    }
}

##4. Initializerを作成する

RealmInitializer.swift
import Foundation
import RealmSwift

struct RealmInitializer {

    static func setUp() {
        // シードデータ作成
        insertSeedData(PrefectureSeed())
        insertSeedData(OwnerSeed())
        print(Realm.Configuration.defaultConfiguration.fileURL!)
    }

    private static func delete<T: RealmSeed>(_ seed: T) where T.SeedType: DBBase {
        // realm
        let realm = try! Realm()
        try! realm.write {
            realm.delete(realm.objects(T.SeedType.self))
        }
    }

    // Realmファイルを作成する
    private static func insertSeedData<T: RealmSeed>(_ seed: T) where T.SeedType: DBBase {
        // realm
        let realm = try! Realm()
        try! realm.write {
            T.items().forEach { val in
                realm.add(val, update: true)
            }
        }
    }
}

##5. ビルドする

AppDelegate.swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // ここに追加
        RealmInitializer.setUp()
        return true
    }
    中略
}

##6. データ確認

コンソールに出力されたパスを開く

open /Users/...

default.realmをRealm Browserで開くと、こんな感じのデータが登録されています。

・prefecture
prefecture.png

・owner
owner.png

・dog
dog.png

##7. 作ったファイルを使う

step1. 対象プロジェクトにdefault.realmをコピーする

作成したデータを使いたいプロジェクトに6.のdefault.realmをコピーする

step2. AppDelegateに処理を追加する

AppDelegate.swift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // ここに追加
        copyRealm()
        return true
    }
    中略
}

extension AppDelegate {
    // Realmファイルをコピーする
    fileprivate func copyRealm() {
        let defaultRealmPath = Realm.Configuration.defaultConfiguration.fileURL!
        // 存在する場合は何もしない
        if FileManager.default.fileExists(atPath: defaultRealmPath.path) {
            return
        }
        let bundleRealmPath = Bundle.main.url(forResource: "default", withExtension: "realm")
        do {
            try FileManager.default.copyItem(at: bundleRealmPath!, to: defaultRealmPath)
        } catch let error {
            print("error copying realm file: \(error)")
        }
    }
}

##8. おまけ

事前データの用意でサブモデルのデータを紐づける際に(例だとOwnerとDog)、

[1, 11, "オーナー1の犬1"]
[1, 12, "オーナー1の犬2"]
[1, 13, "オーナー1の犬3"]
[1, 14, "オーナー1の犬4"]
[1, 15, "オーナー1の犬5"]
[2, 21, "オーナー2の犬1"]
[2, 22, "オーナー2の犬2"]
[2, 23, "オーナー2の犬3"]

こういうのを

[
    1: [
        [11, "オーナー1の犬1"],
        [12, "オーナー1の犬2"],
        [13, "オーナー1の犬3"],
        [14, "オーナー1の犬4"],
        [15, "オーナー1の犬5"]
    ],
    2: [
        [21, "オーナー2の犬1"],
        [22, "オーナー2の犬2"],
        [23, "オーナー2の犬3"]
    ]
]

こうしたかったので、こういうのを用意しました。

18
17
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
18
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?