In Bite #231, we took a look at Realm's new Fine-grained notifications functionality. Today we'll build upon this by checking out another new Realm feature: Queryable, Live Inverse Collections. Whew! That's a fancy name. This feature deserves one though, let's check it out.
Here's a Realm object with a relationship defined on it:
That dogsproperty can be used in a query, and it will even stay updated to reflect changes to the property's value made elsewhere in our app, automatically.
None of that is new though. What is new is the inverse of this mechanic.
LinkingObjects are live and auto-updating. When new relationships are formed or removed, they will update to reflect the new state.
LinkingObjects can be used In queries, natively. (Previously this would need to be done in our code):
// People that have a child that have a parent named Diane.realm.objects(Person).filter("ANY children.parents.name == 'Diane'")// People whose parents have an average age of > 65.realm.objects(Person).filter("parents.@avg.age > 65")
LinkingObjects behave like regular Realm collections:
// Which of my parents are over the age of 56?self.parents.filter("age > 56")// Calculate the age of my parents.self.parents.average("age")
We first looked at Realm way back in Bite #49. It's a great data storage solution for our mobile apps. Today we'll start looking at some of the latest improvements in Realm and the new capabilities they offer. First up is Fine-grained notifications. Let's dive in:
Realm has offered notifications of write operations for a while, they look like this:
These are still around and work great, but it might help to know more about what changed. That's where the new Collection Notifications come in.
Collection notifications give us access the changes that just occurred at a fine-grained level, including the specific indices of insertions, deletions, etc
.Update's values can be easily mapped to NSIndexPath objects suitable for use in table views and collection views.
Here's a complete example showing all of this in action:
classSpaceshipsViewController:UITableViewController{varnotificationToken:NotificationToken?=niloverridefuncviewDidLoad(){super.viewDidLoad()letrealm=try!Realm()letresults=realm.objects(Spaceships).filter("maxSpeed > 0")// Observe Results NotificationsnotificationToken=results.addNotificationBlock{[weakself](changes:RealmCollectionChange)inguardlettableView=self?.tableViewelse{return}switchchanges{case.Initial:// Results are now populated and can be accessed without blocking the UItableView.reloadData()breakcase.Update(_,letdeletions,letinsertions,letmodifications):// Query results have changed, so apply them to the UITableViewtableView.beginUpdates()tableView.insertRowsAtIndexPaths(insertions.map{NSIndexPath(forRow:$0,inSection:0)},withRowAnimation:.Automatic)tableView.deleteRowsAtIndexPaths(deletions.map{NSIndexPath(forRow:$0,inSection:0)},withRowAnimation:.Automatic)tableView.reloadRowsAtIndexPaths(modifications.map{NSIndexPath(forRow:$0,inSection:0)},withRowAnimation:.Automatic)tableView.endUpdates()breakcase.Error(leterror):// An error occurred while opening the Realm file on the background worker threadfatalError("\(error)")break}}}deinit{notificationToken?.stop()}}
We continue our look at frameworks that map JSON into model types today with Decodable by Johannes Lund. Decodable is another fantastic solution for this task. It takes advantage of Swift 2's new error handling functionality, and unlike ObjectMapper (covered in Bite #84), the properties on your models don't need to be optionals. Let's take a closer look:
To get things wired up we just need to implement the Decodableprotocol on our model types, like so:
Decodable also handles nested types and is quite flexible. For example, we aren't even forced to use Decodable on every type. Here we bypass Decodable a bit and instantiate a value for our rankproperty manually:
Some other noteworth Decodable features are its wonderful printable errors, and how easy it is to add custom decode functions for things like parsing custom date formats, etc.
There are plenty (no really, plenty) of options when it comes to parsing JSON into model objects on iOS. We'll be taking a look at some of them from time to time over the coming weeks. First up is ObjectMapper by Hearst. Let's take a look how it works with a fictional set of types:
With ObjectMapper, we implement the Mappableprotocol on our types to support converting to and from JSON:
ObjectMapper can easily handle nested objects, here on our Spaceship model, we've got an optional User property for the captain of the ship.
It also supports subclasses and custom transforms when serializing/deserializing properties. One of the best things about ObjectMapper are the extensions available for other great iOS libraries like Alamofire and Realm (covered in Bite #49). Here's AlamofireObjectMapper in action:
Realm is a database made specifically for running on mobile devices. It works on Mac and iOS devices. (It even supports Android!) It's a great alternative to Core Data or even raw SQLite.
There's plenty to love about Realm, but the best part is it's ultra-simple API:
Define an Object
importRealmSwiftclassSpaceship:Object{dynamicvarname=""dynamicvartopSpeed=0// in km}
varship=Spaceship()ship.name="Outrider"ship.topSpeed=1150vardash=User()dash.firstName="Dash"dash.lastName="Rendar"ship.owner=dash// need one Realm per threadletrealm=Realm()realm.write{realm.add(ship)}
Find Objects
Queries in Realm couldn't be simpler. They are chainable. You can add as many calls to .filter as you'd like. You can sort results using the chainable sorted function.