・モチベーション
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で開くと、こんな感じのデータが登録されています。
##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"]
]
]
こうしたかったので、こういうのを用意しました。