Realm Tutorial: Getting Started

Learn how to use Realm, a popular cross-platform mobile database that is an alternative to Core Data. By Bradley Johnson.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Working With the Realm Browser

One thing you don’t know at this point is where your Realm database lives. There’s a nice trick you can use to find it.

Open MapViewController.swift and import the RealmSwift framework. Add the following line to the top of the file, just below the existing import statements at the top of the file:

import RealmSwift

Now add the following line to viewDidLoad() just after the call to super.viewDidLoad():

print(Realm.Configuration.defaultConfiguration.path!)

This line simply prints the database location to the debug console. It’s a short step to then browse the database using the Realm Browser.

Build and run your app; you’ll see that it reports the location of the database in the Xcode console.

The easiest way to go to the database location is to open Finder, press Cmd-Shift-G and paste in the path your app reported.

Once you open the folder in Finder, you might see one or two files. One of them will be default.realm, which is your database file. The second file, which may or may not be present, is default.realm.lock which prevents modification from other apps while the database is in use.

If you haven’t yet downloaded Realm Browser, download it now from the Mac App Store. Double-click default.realm to open it with Realm Browser:

IntroductionToRealm_RealBrowserCategories

Once the database is open in Realm Browser, you’ll see Category with a 5 next to it. This means that this class contains five records. Click a class to inspect the individual fields contained within.

realm-browser-data

Adding Categories

Now you can implement the logic to set the category of a Specimen.

Open AddNewEntryController.swift and import the RealmSwift framework. Once again, import Realm at the top of the file, just below the existing import statements:

import RealmSwift

Now add the following property to the class:

var selectedCategory: Category!

You’ll use this to store the selected Category.

Next, find unwindFromCategories() and add the following implementation:

if segue.identifier == "CategorySelectedSegue" {
  let categoriesController = segue.sourceViewController as! CategoriesTableViewController
  selectedCategory = categoriesController.selectedCategory
  categoryTextField.text = selectedCategory.name
}

unwindFromCategories() is called when the user selects a category from CategoriesTableViewController, which you set up in the previous step. Here, you retrieve the selected category, store it locally in selectedCategory, and then fill in the text field with the category’s name.

Now that you have your categories taken care of, you can create your first Specimen!

Still in AddNewEntryController.swift, add one more property to the class:

var specimen: Specimen!

This property will store the new specimen object.

Next, add the helper method below to the class:

func addNewSpecimen() {
  let realm = try! Realm() // 1

  try! realm.write { // 2
    let newSpecimen = Specimen() // 3

    newSpecimen.name = self.nameTextField.text! // 4
    newSpecimen.category = self.selectedCategory
    newSpecimen.specimenDescription = self.descriptionTextField.text
    newSpecimen.latitude = self.selectedAnnotation.coordinate.latitude
    newSpecimen.longitude = self.selectedAnnotation.coordinate.longitude

    realm.add(newSpecimen) // 5
    self.specimen = newSpecimen // 6
  }
}

Here’s what the code above does:

  1. You first get a Realm instance, as before.
  2. Here you start the write transaction to add your new Specimen.
  3. Next, you create a new Specimen instance.
  4. Then you assign the Specimen values. The values come from the text input fields in the user interface, the selected categories, and the coordinates from the map annotation.
  5. Then you add the new Specimen to the realm.
  6. Finally, you assign the new Specimen to your specimen property.

You’ll need some sort of validator to make sure all the fields are populated correctly in your Specimen. validateFields() in AddNewEntryController exists to do just this: check for a specimen name and description. Since you’ve just added the ability to assign a category to a specimen, you’ll need to check for that field too.

Still in AddNewEntryController.swift, find the line in validateFields() that looks like this:

if nameTextField.text!.isEmpty || descriptionTextField.text!.isEmpty {

Change that line to this:

if nameTextField.text!.isEmpty || descriptionTextField.text!.isEmpty || selectedCategory == nil {

This verifies that all fields have been filled in and that you’ve selected a category as well.

Next, add the following method to the class:

override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
  if validateFields() {
    addNewSpecimen()
    return true
  } else {
    return false
  }
}

In the above code you call the method to validate the fields; only if everything is filled in do you add the new specimen.

Build and run your app; tap the + button to create a new Specimen. Fill in the name and description, select a Category, and tap Confirm to add your Specimen to the database.

Adding a specimen

The view controller dismisses — but nothing appears to happen. What’s the deal?

Ah — you’ve posted the record to your realm, but you haven’t yet populated the map with your newly discovered specimen!

Retrieving Records

Now that you’ve added a specimen to the database, you want it to show up on the map.

First, take another look at the updated database in the Realm Browser:

Screen Shot 2015-08-26 at 8.43.23 PM

You’ll see your one lonely specimen, with all fields filled along with the latitude and longitude from the MKAnnotation. You’ll also see the link to your specimen’s category — that means your one-to-many Category relationship is working as expected. Click the Category in your Specimen record to view the Category record itself.

Now you need to populate the map in the app.

Open SpecimenAnnotation.swift and add a property to the class:

var specimen: Specimen?

This will hold the Specimen for the annotation.

Next, replace the initializer with the following:

init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, specimen: Specimen? = nil) {
  self.coordinate = coordinate
  self.title = title
  self.subtitle = subtitle
  self.specimen = specimen
}

The change here is to add an option to pass in a Specimen. The specimen will have a default value of nil which means you can omit that argument if you like. That means the rest of the app can continue to call the initializer with just the first three arguments as usual if there’s no specimen.

Now open MapViewController.swift add a new property to the class:

var specimens = try! Realm().objects(Specimen)

Since you want to store a collection of specimens in this property, you simply ask a Realm instance for all objects of type Specimen.

Now you’ll need some sort of mechanism to populate the map. Still in MapViewController.swift, add the following method to the class:

func populateMap() {
  mapView.removeAnnotations(mapView.annotations) // 1

  specimens = try! Realm().objects(Specimen) // 2

  // Create annotations for each one
  for specimen in specimens { // 3
    let coord = CLLocationCoordinate2D(latitude: specimen.latitude, longitude: specimen.longitude);
    let specimenAnnotation = SpecimenAnnotation(coordinate: coord,
      title: specimen.name,
      subtitle: specimen.category.name,
      specimen: specimen)
    mapView.addAnnotation(specimenAnnotation) // 4
  }
}

Taking each numbered comment in turn:

  1. First, you clear out all the existing annotations on the map to start fresh.
  2. Next, you refresh your specimens property.
  3. You then loop through specimens and create a SpecimenAnnotation with the coordinates of the specimen, as well as its name and category.
  4. Finally, you add each specimenAnnotation to the MKMapView.

Now you need to call this method from somewhere. Find viewDidLoad() and add this line to the end of its implementation:

populateMap()

That will ensure the map will be populated with the specimens whenever the map view controller loads.

Finally you just need to modify your annotation to include the specimen name and category. Find unwindFromAddNewEntry(_:) and replace the method with the following implementation:

@IBAction func unwindFromAddNewEntry(segue: UIStoryboardSegue) {

  let addNewEntryController = segue.sourceViewController as! AddNewEntryController
  let addedSpecimen = addNewEntryController.specimen
  let addedSpecimenCoordinate = CLLocationCoordinate2D(latitude: addedSpecimen.latitude, longitude: addedSpecimen.longitude)

  if let lastAnnotation = lastAnnotation {
    mapView.removeAnnotation(lastAnnotation)
  } else {
    for annotation in mapView.annotations {
      if let currentAnnotation = annotation as? SpecimenAnnotation {
        if currentAnnotation.coordinate.latitude == addedSpecimenCoordinate.latitude && currentAnnotation.coordinate.longitude == addedSpecimenCoordinate.longitude {
          mapView.removeAnnotation(currentAnnotation)
          break
        }
      }
    }
  }

  let annotation = SpecimenAnnotation(coordinate: addedSpecimenCoordinate, title: addedSpecimen.name, subtitle: addedSpecimen.category.name, specimen: addedSpecimen)

  mapView.addAnnotation(annotation)
  lastAnnotation = nil;
}

This method is called once you’ve returned from AddNewEntryController and there’s a new specimen to add to the map. When you add a new specimen to the map, it gets the generic annotation icon; now that you have a category, you want to change that icon to the category-specific icon. Here you simply remove the last annotation added to the map (the generic-looking one) and replace it with an annotation that shows the name and category of the specimen.

Build and run your app; create some new specimens of different categories and see how the map updates:

Realm Map Pins

Bradley Johnson

Contributors

Bradley Johnson

Author

Over 300 content creators. Join our team.