7rpn’s blog: うわああああな日常

好きなことをつらつらと。

SwiftでSQLiteが使いたい?ならSwiftyDBが良いよ!

SwiftでSQLiteが使いたいと思ったわけです。
なのでとりあえず"Swift SQLite"みたいな感じで検索するじゃないですか。
一番上に出てきたSwiftDataとかいうのを使おうと思ってgithubを見ると,最終更新が2 years agoなわけです。あれ,やばくね?

もちろん使ってみてもSwift2に対応していないのかエラー出まくり
ほかのSQLiteのライブラリ試してみてもどれも一筋縄ではいかない。

だってRealmがあるもの

どうしてSwiftではSQLiteが打ち棄てられているのでしょうか。

理由は,Realmとかいうスーパーデータベースのせいなんですかね?
SQLiteの後継と言われてるらしくて,かなり盛り上がっています。書き込みも読み込みもSQLiteよりずっと速い。
基本的に今SwiftでDB扱うならまずRealmみたいな雰囲気なんでしょう。多分。

でも,Rubyを使う私たちはActiveRecordでさっと扱えるSQLiteが使いたいんですよ。
RubyでDBをさくっと作ってそれをシームレスにSwiftに渡してiOSアプリを作りたいんです。
Realmは現状JavaとSwift(あとcsv)にしか対応してないっぽいので,ここでRealmを扱うのは避けたい。

そんな風にActiveRecordぽくさっと使えて,今でもちゃんと更新されてるSwiftのSQLiteライブラリはないかな,と探し試すこと数時間。
ありました,その名もSwiftyDB! 日本語でこのライブラリを扱っている記事がなかったのでここに残しておきます。

環境

基本的な使い方

ざっくりとした使い方に触れます。より詳しく知りたい場合はSwiftyDBのサイトをどうぞ。

今回は,Dogという名のテーブルにname:string old:integerのデータを保存するdogtopia.sqliteを作りたいと思います。 そこからデータの保存と取り出しをやりたいと思います。

class Dog : Storable {
    var name: String?
    var old: Int?

    required init() {}
}

おまじないとして,ActiveRecordのようにclassとしてtableの宣言が必要です。カラムの型を一つづつ明示する必要があり。 SwiftyDBでもclass名がそのままtable名になります。


let dogdb = SwiftyDB(databaseName: "dogtopia")

let dog1 = Dog()
dog1.name = "pochi"
dog1.old = 3
dogdb.addObject(dog1,update:true)

SwiftDB()でデータベースを使うことを宣言します。DBが存在していなければDocumentフォルダに勝手に作ってくれるのでとても便利。
DBファイルの名前は上記のコードの場合,"dogtopia.sqlite"になります。

Dog()で新しいデータを作って,プロパティとして情報を入れていきます。 addObjectするだけでデータの保存ができます。楽。


let filter = Filter.equal("old", value: 3)

let result = dogdb.dataForType(Dog.self,matchingFilter: filter)
if let data = result.value{
    data.forEach{
      print($0["name"])
      print($0["old"])
    }
}

dogdb.asyncDataForType(Dog.self,matchingFilter: filter){ (result) -> Void in
  // 処理
}

逆にデータを取り出す際はこんな感じ。Hash的に取り出せます。 dataForTypeでデータベースの中身を取り出して,あとはお好きなようにという感じ。ただOptionalかかってるのでそれは外してください。 filterもかなり楽にかけられます。

非同期処理でDBを取り出すメソッドasyncDataForTypeもあるので,やりたいことがサクッと済ませられる感じ。

ActiveRecordは保存するときにHashっぽくて取り出す時はプロパティですが,SwiftyDBは逆っぽいです。

RubyからSQLiteを渡して使う

自分はSwiftyDB.swiftを直接編集して使っています。

public initの部分で,

let path = NSBundle.mainBundle().pathForResource(databaseName, ofType: "sqlite")

みたいな感じでアプリのrootに保存したDBファイルを読み込みに行くように書き換えてます。Document内に最初からDB保存するとRejectされるっぽいので。

これでRubyで作ったDBをSwiftで扱うアプリが作り放題になりましたね。
ActiveRecordがRealmに対応するのが一番嬉しいんですが,正直当分はなさそうなので,それまではSwiftyDBでいこうと思います。