Search code examples
swiftrealm

Should I create a separate Realm object for custom grouping?


I have been using Realm in an app and love it. Thank you! I have a question I would like to run by you folks and get some advice.

Lets say you have a realm object that contains a date field (simplified example):

class Appointment: Object {

    dynamic var type = ""
    dynamic var date = Date()
}

Now, suppose you have saved thousands of Appointments, and you are going to display these on a tableview or collectionview, grouped by week for example. So the datasource for your view would be something like this.

struct AppointmentsInWeek {
    var startDate: Date?
    var endDate: Date?
    var appointments: [Appointment]
}

So, I have two options in mind I am thinking through with various pros and cons: 
 A) Make AppointmentsInWeek a subclass of Object, save it in the Realm, and use that as the datasource.

PROS:
  • Data for table will be lazy loaded from Realm
  • Simple to use at the moment it is needed.
CONS:
  • Keeping this up to date seems like a challenge. I would probably have some kind of observable looking at the Appointment in Realm and as any are added put them in the appropriate AppointmentWeek

B) Upon loading the screen with the tableview, fetch all appointments, or a subset of them, group them by their appropriate start and end date, and create an AppointmentsInWeek struct to use as the datasource.

PROS:
  • AppointmentsInWeek will always be up to date because it is created on the fly as needed
CONS:
  • We would have to keep all of this in memory, limiting the amount of appointments we could realistically display at once.

I started with option B but I am thinking now it might be better to go with option A. If I do, the biggest issue is making sure the Realm is always up to date when new appointments are added.

Questions

  1. Are there other options I did not consider?
  2. Which sounds like a better option?
  3. Assuming I go with option A, would it make sense to have a class, that lives throughout the life of the app, in charge of observing the Appointments in Realm and when one is added (or changed), add it also to the appropriate AppointmentWeek?

Solution

  • Both options are fine, but I suggest option A. There are a few ways to approach option A.

    First of all, you don't need to keep Appointment and AppointmentsInWeek in sync manually. You can use some combination of object properties, list properties, and linking objects properties to model connections between Appointments and AppointmentsInWeeks. Exactly how you might implement this depends on your app's specific needs, but here's one possibility:

    class Appointment : Object {
        dynamic var type = ""
        dynamic var date = NSDate()
        // Link to the week this appointment lives in, if desired
        var week: AppointmentsInWeek? = nil
    }
    
    class AppointmentsInWeek : Object {
        dynamic var startDate = NSDate()
        dynamic var endDate = NSDate()
        // Add appointment to List whenever it's created
        let appointments = List<Appointment>()
    }
    

    A second possibility is to not use relationships at all, but to use queries instead. Realm supports queries through the Results class. You could add an ignored property on your AppointmentsInWeek class that queries the Realm for all appointments that fall within its date range:

    class Appointment : Object {
        dynamic var type = ""
        dynamic var date = NSDate()
    }
    
    class AppointmentsInWeek : Object {
        dynamic var startDate = NSDate()
        dynamic var endDate = NSDate()
    
        lazy var appointments: Results<Appointment> = {
            // This implementation assumes you can get a reference
            // to the Realm storing your Appointments somehow
            return appointmentsRealm.objects(Appointments.self).filter(NSPredicate(format: "(date >= %@) AND (date < %@)", self.startDate, self.endDate))
        }()
    
        override static func ignoredProperties() -> [String] {
            return ["appointments"]
        }
    }
    

    In either case Realms, lists, and results all update automatically whenever the runloop of the thread they are on (usually the main thread) runs. Realm also supports a variety of notifications in case you need to react to changes manually.