LoginSignup
385
379

More than 5 years have passed since last update.

Realmを使ってデータ管理【Swift編】-その1-

Last updated at Posted at 2014-10-21

皆さん、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がついてないと値が保存されません。

Book.swift
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)を使いましょう!

Book.swift
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しましょう。

Book.swift
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-に続きます。

385
379
5

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
385
379