Navigation

Quick Start

Overview

This page contains information to quickly get Realm Database integrated into your app. Before you begin, ensure you have:

Check Out the Tutorial

This page contains only the essential information that you need to set up a MongoDB Realm application. If you prefer to follow a guided tutorial that shows you step-by-step how to set up a working app, check out the iOS Tutorial where you’ll build a mobile app that connects to the Task Tracker backend.

Import Realm

Near the top of any Swift file that uses Realm, add the following import statement:

import RealmSwift

Initialize the App

To use MongoDB Realm features such as authentication and sync, you must access your Realm app using your Realm app ID. You can find your Realm app ID in the Realm UI.

let app = App(id: "your-realm-app-id")

Define Your Object Model

If have not enabled Realm Sync or you enabled Sync with Development Mode in the Realm UI, you can define your object model directly in code.

Note

If you have enabled Sync but turned off Developer Mode, you can copy and paste the object model definitions that Realm generated for you from the SDKs tab in the Realm UI. You must re-enable Developer Mode if you want to make changes to the object model definition from client side code. See Configure Your Data Model.

class Task: Object {
    @objc dynamic var _id: ObjectId = ObjectId.generate()

    // When configuring Sync, we selected `_partition` as the partition key.
    // A partition key is only required if you are using Sync.
    @objc dynamic var _partition: String = ""

    @objc dynamic var name: String? = nil
    @objc dynamic var complete = false

    override static func primaryKey() -> String? {
        return "_id"
    }

    convenience init(partition: String, name: String) {
        self.init()
        self._partition = partition
        self.name = name
    }
}

Authenticate a User

When you have enabled anonymous authentication in the Realm UI, users can immediately log into your app without providing any identifying information:

app.login(credentials: Credentials.anonymous()) { (user, error) in
    // Remember to dispatch back to the main thread in completion handlers
    // if you want to do anything on the UI.
    DispatchQueue.main.sync {
        guard error == nil else {
            print("Login failed: \(error!)")
            return
        }

        // Now logged in, do something with user

    }
}

Realm provides many additional ways to authenticate, register, and link users.

Open a Realm

Once you have enabled Realm Sync and authenticated a user, you can open a realm asynchronously by calling asyncOpen, passing in the user’s Configuration object, which includes the partition name. The following code demonstrates this:

let user = app.currentUser()
let partitionValue = "myPartition"

Realm.asyncOpen(configuration: user!.configuration(partitionValue: partitionValue)) { realm, error in
   guard let realm = realm else {
      // handle error
      return
   }
   // Realm successfully opened
}

See also

Sync Data

Create, Read, Update, and Delete Objects

Once you have opened a realm, you can modify it and its objects in a write transaction block.

To create a new Task, instantiate the Task class and add it to the realm in a write block:

let task = Task(partition: partitionValue, name: "New Task")
try! self.realm.write {
    self.realm.add(task)
}

You can retrieve a live collection of all tasks in the realm:

// All tasks in the realm
let tasks = realm.objects(Task.self)

You can also filter that collection using a filter:

// You can also filter a collection
let tasksThatBeginWithA = tasks.filter("name beginsWith 'A'")
let completeTasks = tasks.filter("complete = true")

To modify a task, simply update its properties in a write transaction block:

let task = tasks[someIndex]

// All modifications to a realm must happen in a write block.
try! realm.write {
    task.complete = true
}

Finally, you can delete a task:

let task = tasks[someIndex]

// All modifications to a realm must happen in a write block.
try! realm.write {
    // Delete the Task.
    realm.delete(task)
}

Watch for Changes

You can watch a realm, collection, or object for changes with the observe method.

Note

Be sure to retain the notification token returned by observe as long as you want to continue observing. When you are done observing, invalidate the token to free the resources.

// Retain notificationToken as long as you want to observe
notificationToken = tasks.observe { (changes) in
     switch changes {
     case .initial:
         // Results are now populated and can be accessed without blocking the UI
     case .update(_, let deletions, let insertions, let modifications):
         // Query results have changed.
         print("Deleted indices: ", deletions)
         print("Inserted indices: ", insertions)
         print("Modified modifications: ", modifications)
     case .error(let error):
         // An error occurred while opening the Realm file on the background worker thread
         fatalError("\(error)")
     }
}

// Later, when done observing
notificationToken.invalidate()

Log Out

Once logged in, you can log out:

app.currentUser()?.logOut() { (error) in
    // Logged out or error occurred
}

Complete Example

Run the complete example by replacing the app ID with your Realm app ID and navigating to the ExampleViewController in an app.

import UIKit
import RealmSwift

let app = App(id: "<your-app-id>") // replace this with your App ID

class Task: Object {
    @objc dynamic var _id: ObjectId = ObjectId.generate()
    // When configuring Sync, we selected `_partition` as the partition key.
    // A partition key is only required if you are using Sync.
    @objc dynamic var _partition: String = ""
    @objc dynamic var name: String = ""
    @objc dynamic var owner: String? = nil
    @objc dynamic var status: String = ""
    override static func primaryKey() -> String? {
        return "_id"
    }

    convenience init(partition: String, name: String) {
        self.init()
        self._partition = partition;
        self.name = name;
    }
}

class ExampleViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad();
        logInAndRunExample()
    }

    func logInAndRunExample() {
        print("Attempting to log in")
        app.login(credentials: Credentials.anonymous()) { [weak self](user, error) in
            // Remember to dispatch back to the main thread in completion handlers
            // if you want to do anything on the UI.
            DispatchQueue.main.sync {
                guard error == nil else {
                    print("Login failed: \(error!)")
                    return
                }

                print("Login succeeded!");

                self!.runExample()
            }
        }
    }

    func runExample() {
        // Now logged in, do something with user
        let user = app.currentUser()
        let partitionValue = "myPartition"

        var configuration = user!.configuration(partitionValue: partitionValue)
        configuration.objectTypes = [Task.self]
        let realm = try! Realm(configuration: configuration)

        // All dogs in the realm
        let tasks = realm.objects(Task.self)

        // Retain notificationToken as long as you want to observe
        let notificationToken = tasks.observe { (changes) in
            switch changes {
            case .initial: break
                // Results are now populated and can be accessed without blocking the UI
            case .update(_, let deletions, let insertions, let modifications):
                // Query results have changed.
                print("Deleted indices: ", deletions)
                print("Inserted indices: ", insertions)
                print("Modified modifications: ", modifications)
            case .error(let error):
                // An error occurred while opening the Realm file on the background worker thread
                fatalError("\(error)")
            }
        }

        let task = Task(partition: partitionValue, name: "Do laundry")
        try! realm.write {
            realm.deleteAll()
            realm.add(task)
        }
        let anotherTask = Task(partition: partitionValue, name: "App design")
        try! realm.write {
            realm.add(anotherTask)
        }

        // You can also filter a collection
        let tasksThatBeginWithA = tasks.filter("name beginsWith 'A'")
        print("A list of all tasks that begin with A: \(tasksThatBeginWithA)")

        let taskToUpdate = tasks[0]

        // All modifications to a realm must happen in a write block.
        try! realm.write {
            taskToUpdate.status = "InProgress"
        }

        let tasksInProgress = tasks.filter("status = %@", "InProgress")
        print("A list of all tasks in progress: \(tasksInProgress)")

        let taskToDelete = tasks[0]
        // All modifications to a realm must happen in a write block.
        try! realm.write {
            // Delete the Task.
            realm.delete(taskToDelete)
        }

        print("A list of all tasks after deleting one: \(tasks)")

        app.currentUser()?.logOut() { (error) in
            // Logged out or error occurred
        }

        // Invalidate notification tokens when done observing
        notificationToken.invalidate()
    }
}

Output

Running the above code should output something like the following:

Attempting to log in
Login succeeded!
... Sync: Connection[1]: Session[1]: client_reset_config = false, Realm exists = true, async open = false, client reset = false
Deleted indices:  []
Inserted indices:  [0]
Modified modifications:  []
A list of all tasks that begin with A: Results<Task> <0x7fd15d60a960> (
   [0] Task {
      _id = 5f3c29...;
      _partition = myPartition;
      name = App design;
      owner = (null);
      status = ;
   }
)
Deleted indices:  []
Inserted indices:  [1]
Modified modifications:  []
A list of all tasks in progress: Results<Task> <0x7fd15d60bd20> (
   [0] Task {
      _id = 5f3c29...;
      _partition = myPartition;
      name = Do laundry;
      owner = (null);
      status = InProgress;
   }
)
Deleted indices:  []
Inserted indices:  []
Modified modifications:  [0]
A list of all tasks after deleting one: Results<Task> <0x7fd15d55cbc0> (
   [0] Task {
      _id = 5f3c29...;
      _partition = myPartition;
      name = App design;
      owner = (null);
      status = ;
   }
)
... Sync: Connection[1]: Disconnected