皆さん、Swiftでガリガリ開発してますか?
Objective-Cから変わりすぎて涙目になりながら開発してますが、
そんな中データ管理にSwiftでもMagicalRecord使おうかと思ってましたが
言語も新しくなった事だし、何か代わりがないかなぁと探していたところ
Realmに出会いました。
実際に使ってみたので、その使用感をお伝えできればと思います。
環境
- x-code 6.0
- swift
- os:ios
- realm 0.83
Realmとは
CoreDataやSQLiteに変わる次世代Mobileデータベースみたい。
Androidでも使えるので移植するときにインタフェースも統一されてて移植しやすいよね!
詳しく知りたい方はここを見ればいいと思います。
なぜRealmを選んだのか
iOSアプリを作ってると、まだAndroidアプリがなかったら必ずと言っていいほど
Androidアプリへの移植が話しにあがってきます。
そのときになるべく移植コストを減らしたいのでAndroid/iOSに対応しているライブラリを選びたいところです。
Realmは両対応してたのでとりあえず使ってみようと思いました。
インストール
公式がみればよほどの事がない限りインストールできるので
ここを参照して頑張ってインストールしましょう。
保存される場所
標準ではDocumets/default.realmに保存されます。
import Realm
// xxxx/Documents/default.realm
println(RLMRealm.defaultRealmPath())
オブジェクトの保存
今回の例では新しくBookオブジェクトを作って保存してみます。
Realmで扱うためにはRLMObjectを継承して、プロパティはdynamicで宣言します。
プロパティにdynamicがついてないと値が保存されません。
import Foundation
import Realm
class Book : RLMObject {
dynamic var isbn = ""
dynamic var name = ""
dynamic var price = 0
}
実際に保存してみます。
保存の仕方は明示的にTransactionで保存する方式とBlockで保存するがあります。
単一での保存と複数での保存どちらも対応しています。
import Realm
let realm = RLMRealm.defaultRealm()
// Bookオブジェクト生成.
let book = Book()
book.isbn = "999999"
book.name = "realm sample"
book.price = 100
// Bookオブジェクトを保存.
realm.beginWriteTransaction()
realm.addObject(book)
realm.commitWriteTransaction()
// 先ほどのBookオブジェクトを取得
// Class.allObjectsで全オブジェクト取得.
for realmBook in Book.allObjects() {
// book name:realm sample
println("book name:\((realmBook as Book).name)")
}
let book2 = Book()
book2.isbn = "999998"
book2.name = "realm tutorial 1"
book2.price = 1000
// Blockでの保存の仕方.
realm.transactionWithBlock() {
realm.addObject(book2)
}
for realmBook in Book.allObjects() {
// book name:realm sample
// book name:realm tutorial 1
println("book name:\((realmBook as Book).name)")
}
という感じで簡単に保存できます。
オブジェクトの検索
先ほどの保存したBookオブジェクトを検索してみましょう。
検索方法は文字列とNSPredicateの2パターンに対応しています。
どちらの方法でも戻り値はRLMResultsです。
let realm = RLMRealm.defaultRealm()
// 文字列検索.
// 戻り値はRLMArray!
let results = Book.objectsWhere("isbn = '999999'")
for realmBook in results {
// book name:realm sample
println("book name:\((realmBook as Book).name)")
}
// NSPredicate検索.
let results2 = Book.objectsWithPredicate(NSPredicate(format: "isbn = %@", "999998"))
for realmBook in results2 {
// book name:realm tutorial 1
println("book name:\((realmBook as Book).name)")
}
Objective-C版ではobjectForPrimaryKey:primaryKey:というメソッドで
一つだけとってくることが可能ですが、Swift版にはないみたいなので
ちょっと使いやすくするためにBookオブジェクトを拡張してみましょう。
追記 2015/03/30
コメントで
Swiftの規則により、objectForPrimaryKey:primaryKey:というクラスメソッドはファクトリメソッド扱いになる>ので、convenience init!(forPrimaryKey primaryKey: AnyObject!)というコンストラクタにマッピングされています。
そのため、プライマリキーでオブジェクトを取ってくる場合は、let book = Book(forPrimaryKey: "999999")のように書きます。
との貴重な情報を頂いたのでむしろ拡張しなくてObject(forPrimaryKey:value)を使いましょう!
import Foundation
import Realm
class Book : RLMObject {
dynamic var isbn = ""
dynamic var name = ""
dynamic var price = 0
// isbnを指定して結果を返す.
class func find(isbn:String) -> Book? {
let result = Book.objectsWithPredicate(NSPredicate(format: "isbn = %@", isbn))
if let books = result {
return books.firstObject() as? Book
}
return nil
}
}
定義したメソッドを実行したいですが、この通り実行すると
migration errorが発生するので、使い方だけ感じ取ってください。
Migrationに関しては別途記述します。
// Migration Errorが発生する!
let realm = RLMRealm.defaultRealm()
// 実装したメソッドで検索.
// すっきり!
// 標準で実装されているので下記が正しい
//if let book = Book.find("999998") {
// // book name:realm tutorial 1
// println(book.name)
//}
// こっちがBest!
if let book = Book(forPrimaryKey: "999998") {
// book name:realm tutorial 1
println(book.name)
}
オブジェクトの削除
先ほど定義したオブジェクトを削除してみましょう。
let realm = RLMRealm.defaultRealm()
// 先ほど保存したisbn=999999を削除.
realm.beginWriteTransaction()
realm.deleteObjects(Book.objectsWhere("isbn = '999999'"))
realm.commitWriteTransaction()
オブジェクトの更新
追加・削除できるなら当然更新もやりたい!
ただ今のままだとprimary keyの指定がないので更新できません。
ですので、primary keyの指定を行います。
class funcで定義されてますので、そちらをoverrideしましょう。
import Foundation
import Realm
class Book : RLMObject {
dynamic var isbn = ""
dynamic var name = ""
dynamic var price = 0
// primaryKeyの指定.
override class func primaryKey() -> String {
return "isbn"
}
// isbnを指定して結果を返す.
class func find(isbn:String) -> Book? {
let result = Book.objectsWithPredicate(NSPredicate(format: "isbn = %@", isbn))
if let books = result {
return books.firstObject() as? Book
}
return nil
}
}
今回はisbnをprimaryKeyにしています。
更新する際にはaddOrUpdateObjectメソッドを使います。
primaryKeyのオブジェクトが存在しない場合は追加、存在する場合は更新になります。
let realm = RLMRealm.defaultRealm()
let book3 = Book()
book3.isbn = "999997"
book3.name = "swift or objective-c"
book3.price = 1500
realm.beginWriteTransaction()
// PrimaryKeyの指定がない場合はException発生!.
realm.addOrUpdateObject(book3)
realm.commitWriteTransaction()
let results = Book.objectsWhere("isbn = '999997'")
for realmBook in results {
// book name:swift or objective-c
// book price:1500
println("book name:\((realmBook as Book).name)")
println("book price:\((realmBook as Book).price)")
}
let book3_v2 = Book()
book3_v2.isbn = "999997"
book3_v2.name = "swift1.0 or swift1.1"
book3_v2.price = 2500
realm.beginWriteTransaction()
realm.addOrUpdateObject(book3_v2)
realm.commitWriteTransaction()
let results_v2 = Book.objectsWhere("isbn = '999997'")
for realmBook in results_v2 {
// 更新されてる!
// book name:swift1.0 or swift1.1
// book price:2500
println("book name:\((realmBook as Book).name)")
println("book price:\((realmBook as Book).price)")
}
たいした事書いてないになぜかめちゃくちゃ長くなったのでRealmを使ってデータ管理【Swift編】-その2-に続きます。