{"id":4858,"date":"2015-10-27T16:37:44","date_gmt":"2015-10-27T16:37:44","guid":{"rendered":"https:\/\/redbooth.com\/engineering\/?p=4858"},"modified":"2015-10-28T10:32:15","modified_gmt":"2015-10-28T10:32:15","slug":"realmresultscontroller","status":"publish","type":"post","link":"https:\/\/redbooth.com\/engineering\/ios\/realmresultscontroller","title":{"rendered":"RealmResultsController"},"content":{"rendered":"<p><iframe loading=\"lazy\" width=\"100px\" height=\"20px\" src=\"https:\/\/ghbtns.com\/github-btn.html?user=redbooth&amp;repo=RealmResultsController&amp;type=star&amp;count=true\" frameborder=\"0\" scrolling=\"0\"><\/iframe><\/p>\n<h2><\/h2>\n<h2><strong>What is it?<\/strong><\/h2>\n<p>In a single phrase, we can say that<\/p>\n<blockquote><p><a href=\"https:\/\/github.com\/redbooth\/RealmResultsController\" target=\"_blank\">RealmResultsController<\/a> is a CoreData&#8217;s `NSFetchedResultsController` equivalent for\u00a0<a href=\"https:\/\/realm.io\">Realm<\/a>\u00a0written in Swift<\/p><\/blockquote>\n<p>The Redbooth iOS App has a heavy use of `CoreData` and `NSFetchedResultsController`, so when we decided to start using Realm we faced our first problem, there was no equivalent for it. We looked at the existing libraries (like <a href=\"https:\/\/github.com\/Roobiq\/RBQFetchedResultsController\">RBQFetchedResultsController<\/a>) but at the moment it was written in Objc and we wanted something purely Swift 2.0 and with some extra features. At that point, we decided to write our own solution and make it open source!<\/p>\n<p>If you are not familiarized with `NSFetchedResultsController` (<a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/CoreData\/Reference\/NSFetchedResultsController_Class\/\">Apple Docs<\/a>), it allows you to efficiently manage the results returned from a Core Data fetch request to provide data for a `UITableView` object. `NSFetchedResultsController` monitors changes in DB objects and notify the view about those changes allowing you to be reactive about them.<\/p>\n<p>We love `Realm`, is faster than `CoreData`, but we think it needed a feature like this to make it even better. <a href=\"https:\/\/github.com\/redbooth\/realmresultscontroller\">`RealmResultsController`<\/a>\u00a0does the same for a Realm request with a couple of extra features.<\/p>\n<p><a href=\"https:\/\/github.com\/redbooth\/RealmResultsController\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"  aligncenter wp-image-4874\" src=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2015\/10\/GitHub_Logo1-300x123.png\" alt=\"GitHub_Logo\" width=\"134\" height=\"55\" srcset=\"https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2015\/10\/GitHub_Logo1-300x123.png 300w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2015\/10\/GitHub_Logo1.png 1000w\" sizes=\"auto, (max-width: 134px) 100vw, 134px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>How it works<\/h2>\n<h4>Realm Limitations<\/h4>\n<p>There are two important limitations to consider when building an add-on for Realm<\/p>\n<ul>\n<li>There aren&#8217;t fine-grained notifications, we can&#8217;t know easily when an object has changed in a Realm, only when a write transaction finishes.<\/li>\n<li>The `Objects` are not thread-safe so our library has to work around that<\/li>\n<\/ul>\n<h4>Solutions<\/h4>\n<p>We built a `Realm` proxy that implements the same functions (add, create, delete&#8230;) and ends calling the original ones, but in the middle allows us to detect all the operations done in realm objects during a transaction.<\/p>\n<p>You must use these methods so the RRC can listen to all the changes in Realm.<\/p>\n<pre class=\"lang:swift decode:true \">\/\/ Basic operations\r\nrealm.write {\r\n  realm.addNotififed(myObject, update: true) \/\/ add the object or update if    exist\r\n  realm.createNotified(myObject) \/\/ create the object in realm\r\n  realm.deleteNotified(myObject) \/\/ delete the object from realm\r\n  myObject.notifyChange() \/\/ just notify the RRC that the object has change    d in some way\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>The library does all the hard work in background, mantaining an updated cache and calculating the indexPaths for each operation. But since `Realm` Objects are not thread safe. Instead of sending `Realm` objects directly to the RRC, we mirror them using `Reflection` in swift, so we end up with an identical object that is `NOT` associated to any realm and therefore it is thread-safe to operate with.<\/p>\n<p>The RRC does all operations in these thread-safe objects, and for the public API, we offer two solutions:<\/p>\n<ul>\n<li>When initalizing the RRC, you can pass a `mapper` function (T -&gt; U) from your Realm.Object (T) to another non-realm object (U). If you do so, the RRC delegate methods will return those mapped non-realm objects intead of the original ones.<\/li>\n<li>If you don&#8217;t pass any mapper, the RRC will just return the mirrored objects (remember they are not actually inside any Realm, i.e. they are thread safe)<\/li>\n<\/ul>\n<pre class=\"lang:swift decode:true\">\/\/Example initalizing a RRC with a mapper\r\nlet rrc = RealmResultsController&lt;TaskModel, Task&gt;(request: request, sectionKeyPath: sectionKeypath, mapper: Task.map, filter: MyFilterFunc)\r\n\r\n\/\/Without a mapper\r\nlet rrc = RealmResultsController&lt;TaskModel, TaskModel&gt;(request: request, sectionKeyPath: sectionKeypath)<\/pre>\n<blockquote><p>For more details about all the RRC methods, initializers, etc&#8230; please take a look to our <a href=\"https:\/\/github.com\/redbooth\/RealmResultsController\">Repository<\/a><\/p><\/blockquote>\n<p>For reference, this is a diagram of the RRC structure:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/github.com\/redbooth\/RealmResultsController\/raw\/master\/Images\/scheme.png\" alt=\"\" width=\"1061\" height=\"522\" \/><\/p>\n<h4><\/h4>\n<h4>I want to use it in my App!!<\/h4>\n<p>Ok, let&#8217;s say we have a Realm database with a model called `Task` and a model called `Project` and we want to show these `Task`s in a `UITableView`, but only the not resolved ones that belong to me.<\/p>\n<p>Also, we want to sort them by Name and organize them in sections depending on which `Project` they belong to.<\/p>\n<pre class=\"lang:swift decode:true\">import RealmSwift\r\n\r\nclass Task: Object {\r\n  dynamic var id: Int = 0\r\n  dynamic var title: String = \"Default\"\r\n  dynamic var resolved: Bool = false\r\n  dynamic var projectID: Int = 0\r\n  dynamic var project: Project?\r\n\r\n  \/\/ For the RRC to work, all the used Objects must have a primaryKey\r\n  override static func primaryKey() -&gt; String? {\r\n    return \"id\"\r\n  }\r\n\r\n  func taskBelongsToMe() -&gt; Bool {\r\n    \/\/ Check if the task is mine\r\n  }\r\n\r\n  func mapToPOSO() -&gt; TaskPOSO {\r\n    \/\/ mapper func\r\n  }\r\n}\r\n\r\nclass Project: Object {\r\n  dynamic var id: Int\r\n  dynamic var name: String\r\n\r\n  override static func primaryKey() -&gt; String? {\r\n    return \"id\"\r\n  }\r\n}\r\n\r\nclass TaskPOSO {\r\n  \/\/ Plain old swift object, thread-safe and ready to use in the view\r\n}<\/pre>\n<h4><\/h4>\n<h4>First step: initialize the RRC<\/h4>\n<p>First, we need a `RealmRequest` object, it represents what we want to fetch from DB.<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Fetch the not resolved tasks\r\nlet predicate = NSPredicate(format: \"resolved == 0\")\r\n\r\n\/\/ The first SortDescriptor must be equal to the SectionKeyPath (if any)\r\n\/\/ There must be always at least one SortDescriptor\r\n\/\/ Sort by \"projectID\" and then by \"name\"\r\nlet sortDescriptors = [SortDescriptor(property: \"projectID\"),\r\nSortDescriptor(property: \"name\")]\r\n\r\n\/\/ We create the request with the predicate and the sortDescriptors\r\n\/\/ indicating in which realm do we want to make the fetch\r\nlet request = RealmRequest(predicate: predicate,\r\nrealm: myRealm,\r\nsortDescriptors: sortDescriptors)<\/pre>\n<p>With the `RealmRequest` we can initialize our `RRC`.<br \/>\nThis is an `RRC` that fetches `Task` and maps them to `TaskPOSO` objects<\/p>\n<pre class=\"lang:swift decode:true\">let rrc = RealmResultsController&lt;Task, TaskPOSO&gt;(\r\n  request: request,\r\n  sectionKeyPath: \"projectID\",\r\n  mapper: Task.mapToPOSO,\r\n  filter: { $0.taskBelongsToMe() }\r\n)\r\n\r\n\/\/ In case you are wondering what \"filter\" is:\r\n\/\/ NSPredicate is very limited sometimes, you can only use it with Realm stored properties\r\n\/\/ With this optional func you can apply an extra filter\r\n\/\/ to your objects calling functions or computed properties<\/pre>\n<p>There is a delegate protocol that you should conform to in order to receive all the RRC notifications:<\/p>\n<pre class=\"lang:swift decode:true\">rrc.delegate = self<\/pre>\n<p>Then, to start receiving updates, we just need to:<\/p>\n<pre class=\"lang:swift decode:true\">rrc.performFetch()<\/pre>\n<p>The Delegate methods are almost equal to the `NSFetchResultsController` ones and you will receive updates the same way you did with `NSFetchResultsController`:<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ You must implement them all\r\n\r\nfunc willChangeResults(controller: AnyObject)\r\nfunc didChangeObject(controller: AnyObject, object: U, oldIndexPath: NSIndexPath, newIndexPath: NSIndexPath, changeType: RealmResultsChangeType)\r\nfunc didChangeSection(controller: AnyObject, section: RealmSection, index: Int, changeType: RealmResultsChangeType)\r\nfunc didChangeResults(controller: AnyObject)<\/pre>\n<p>A generic implementation could be:<\/p>\n<pre class=\"lang:swift decode:true\">func willChangeResults(controller: AnyObject) {\r\n  tableView.beginUpdates()\r\n}\r\n\r\nfunc didChangeObject(controller: AnyObject, object: U, oldIndexPath: NSIndexPath, newIndexPath: NSIndexPath, changeType: RealmResultsChangeType) {\r\n  switch changeType {\r\n    case .Delete:\r\n      tableView.deleteRowsAtIndexPaths([newIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)\r\n    case .Insert:\r\n      tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)\r\n    case .Move:\r\n      tableView.deleteRowsAtIndexPaths([oldIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)\r\n      tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)\r\n    case .Update:\r\n      tableView.reloadRowsAtIndexPaths([newIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)\r\n   }\r\n}\r\n\r\nfunc didChangeSection(controller: AnyObject, section: RealmSection, index: Int, changeType: RealmResultsChangeType) {\r\n  switch changeType {\r\n    case .Delete:\r\n      tableView.deleteSections(NSIndexSet(index: index), withRowAnimation: UITableViewRowAnimation.Automatic)\r\n    case .Insert:\r\n      tableView.insertSections(NSIndexSet(index: index), withRowAnimation: UITableViewRowAnimation.Automatic)\r\n    default:\r\n      break\r\n  }\r\n}\r\n\r\nfunc didChangeResults(controller: AnyObject) {\r\n  tableView.endUpdates()\r\n}<\/pre>\n<p>At this point we have the `RRC` fully configured and ready to use, but we need it to integrate it with the `UITableViewDataSource` methods:<\/p>\n<pre class=\"lang:swift decode:true\">func numberOfSectionsInTableView(tableView: UITableView) -&gt; Int {\r\n  return rrc.numberOfSections\r\n}\r\n\r\nfunc tableView(tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {\r\n  return rrc.numberOfObjectsAt(section)\r\n}\r\n\r\nfunc tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -&gt; UITableViewCell {\r\n  var cell = tableView.dequeueReusableCellWithIdentifier(\"taskCell\")\r\n  if cell == nil {\r\n    cell = UITableViewCell(style: .Default, reuseIdentifier: \"taskCell\")\r\n  }\r\n  \/\/ This is the correct way to access an object fetched by the RRC\r\n  \/\/ This object will be of the Type specified when the RRC was created\r\n  let task = rrc.objectAt(indexPath) \/\/ task is a TaskPOSO Object\r\n\r\n  cell?.textLabel?.text = task.name + \" :: \" + String(task.projectID)\r\n  return cell!\r\n}<\/pre>\n<p>Now we are settled!!<br \/>\nIf we create a new Task that meets the requirements, modify or delete a existing one, we will be notified.<\/p>\n<pre class=\"lang:swift decode:true\">\/\/ Create new object\r\nrealm.write {\r\n  let newTask = Task()\r\n  newTask.id = 123\r\n  newTask.name = \"1. first task\"\r\n  newTask.projectID = 1\r\n  realm.addNotified(newTask)\r\n}\r\n\r\n\/\/ Update a existing one\r\nrealm.write {\r\n  let task = realm.objectForPrimaryKey(Task, key: 123)\r\n  task.name = \"2. new name!\"\r\n  task.notifyChange()\r\n}\r\n\r\n\/\/ Delete existing object\r\nrealm.write {\r\n  let task = realm.objectForPrimaryKey(Task, key: 123)\r\n  realm.deleteNotified(task)\r\n}<\/pre>\n<p>For a more detailed working example, check out the\u00a0<a href=\"https:\/\/github.com\/redbooth\/RealmResultsController\">RealmResultsController<\/a>\u00a0Repository<\/p>\n<p>&nbsp;<\/p>\n<h4>Conclusion<\/h4>\n<p>We&#8217;ve been really happy working with Realm, and now that we have an alternative to `NSFetchResultsController` even more. `RealmResultsController` aims to extend and improve Realm adding a feature that is very well known for `CoreData` users.<\/p>\n<p>It also adds a couple of features (mapping and filtering) that weren&#8217;t in the original controller but we think that they can be really useful to make better and more explicit request to Realm. Also, adding a mapping feature allows us to separate the view from the model, we don&#8217;t receive models at the view level.<\/p>\n<p>`RealmResultsController` can help you be more reactive in your views to model changes in your database without using pure reactive programming.<\/p>\n<p>It is 100% covered with tests, thread-safe and a reliable library that we use in our own app. We&#8217;ll be happy to receive all the feedback you have about it, if you detect a bug or have a feature request, please fill an Issue in our <a href=\"https:\/\/github.com\/redbooth\/RealmResultsController\">Repository<\/a>\u00a0or just send a PR directly \ud83d\ude42<\/p>\n<p><a href=\"https:\/\/github.com\/redbooth\/RealmResultsController\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"  aligncenter wp-image-4874\" src=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2015\/10\/GitHub_Logo1-300x123.png\" alt=\"GitHub_Logo\" width=\"134\" height=\"55\" srcset=\"https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2015\/10\/GitHub_Logo1-300x123.png 300w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2015\/10\/GitHub_Logo1.png 1000w\" sizes=\"auto, (max-width: 134px) 100vw, 134px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>What is it? In a single phrase, we can say that RealmResultsController is a CoreData&#8217;s `NSFetchedResultsController` equivalent for\u00a0Realm\u00a0written in Swift The Redbooth iOS App has a heavy use of `CoreData` and `NSFetchedResultsController`, so when we decided to start using Realm we faced our first problem, there was no equivalent for it. We looked at the <a class=\"read-more\" href=\"https:\/\/redbooth.com\/engineering\/ios\/realmresultscontroller\">&hellip;&nbsp;<span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":44,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41],"tags":[45,42,43,46,44],"class_list":["post-4858","post","type-post","status-publish","format-standard","hentry","category-ios","tag-coredata","tag-ios","tag-realm","tag-realmresultscontroller","tag-swift"],"_links":{"self":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts\/4858","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/users\/44"}],"replies":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/comments?post=4858"}],"version-history":[{"count":0,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts\/4858\/revisions"}],"wp:attachment":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/media?parent=4858"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/categories?post=4858"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/tags?post=4858"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}