Realm is the mobile database to use for those looking for a modern, fast, and off-line centric solution that works across all major mobile platforms. When you’re starting from scratch, then it’s easy to just dive in and get going. But sometimes you will have existing data that you need to convert over first. In this article, we will walk through on how you can accomplish this task with a little help from Xcode and Swift.
The first thing you should do is check out the Realm Cocoa Converter. This is an officially supported solution designed by the Engineers over at Realm that can both import into and export from Realm databases. It currently supports CSV, XLSX, and JSON, with SQLite in their plans. If the converter doesn’t support SQLite just yet, we will need to do it ourselves.
Creating the Realm Model Layer
Let’s look at a simple SQLite Database and create the appropriate Realm model layer in Swift.
SQLite Database Structure:
Swift Model:
// Person model
class Person: Object {
dynamic var id = 0
dynamic var name = ""
dynamic var birthdate = Date()
let dogs = LinkingObjects(fromType: Dog.self, property: "owner")
override static func primaryKey() -> String? {
return "id"
}
}
// Dog model
class Dog: Object {
dynamic var id = 0
dynamic var name = ""
dynamic var breed = ""
dynamic var owner: Person? // to-one relationships must be optional
override static func primaryKey() -> String? {
return "id"
}
}
When creating Realm Model objects, for the most part the properties can be one-for-one matches of the column names in SQLite. But it’s important to remember that Realm is not a relational database. And thus, it does not use foreign keys to create links between tables. To create these relationships, you must instead declare a property with the type of your Object subclass.
class Dog: Object {
…
dynamic var owner: Person?
This example will allow a Dog to have one owner as a Person Object. But these links areunidirectional, meaning while you can look at a Dog and see who the owner is, you can’t view the a Person to see which Dogs it owns unless you create this inverse relationship. This can be done manually, but a less error-prone option is to use a property of LinkingObjects.
class Person: Object {
…
let dogs = LinkingObjects(fromType: Dog.self, property: "owner")
LinkingObjects will automatically add the property Dogs to Person. Any Dog that has the set as this Person will show up in this property. This allows for a one-to-many relationship as well, since LinkingObjects returns a RealmCollection which can be iterated through to navigate all the Dogs a Person owns.
Reading data from a SQLite database
Once your model is created, the next step is to read out the contents of the SQLite database. In Swift, a convenient library to do this is libsqlite3. Using this, you can create queries to read out the data from the SQLite, table by table.
let query = "select * from Person"
// Open SQLite database
var db: OpaquePointer? = nil
if sqlite3_open(fileURL, &db) == SQLITE_OK {
// Run SELECT query from db
var statement: OpaquePointer? = nil
if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {
// Loop through all results from query
while sqlite3_step(statement) == SQLITE_ROW {
…
}
}
}
else {
let errmsg = String(cString: sqlite3_errmsg(db))
print("error running query: \(errmsg)")
}
}
else {
print("error opening database")
}
Copying data to the Realm database
As you are looping through the results from SQLite, instantiate a Realm object and add copy the values over.
// Create object for Realm
let realmPersonItem = Person()
let id = sqlite3_column_int64(statement, 0)
print("id = \(id); ", terminator: "")
realmPersonItem.id = Int(id)
let name = sqlite3_column_text(statement, 1)
if name != nil {
let nameString = String(cString:name!)
print("name = \(nameString); ", terminator: "")
realmPersonItem.name = nameString
} else {
print("name not found", terminator: "")
}
…
Once you are done, make sure to write the object as a transaction to the Realm database.
// Add to the Realm inside a transaction
try! realm.write {
realm.add(realmPersonItem)
}
Repeat for all the tables for your database.
Export Realm database file
Once the Realm database is complete, it is time to package and copy it for use in your mobile application. There is a default location where your Realm database is located, which you can find here:
let defaultRealmPath = Realm.Configuration.defaultConfiguration.fileURL
Depending on your needs, you may want to create a compact version or encrypted version of the database for export. If so, you can use the writeCopy method to do just that. Now you will have a pre-initialized Realm database that can be used for all your mobile projects!
Where to go from here?
You can download a completed project of everything we walked through here. With your Realm set, you can get started using it by going through the official documentation.
If you have any questions or comments on this tutorial or mobile development in general, feel free to contact us.