Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern for Realm persistence

Tags:

ios

realm

I'm using Realm in a App and I'm trying to abstract much as possible so that in the future I can swap database providers without too much change.

This pattern has worked well although I'm concerned about the following.

  • Is creating a new realm object everytime a overhead (My current understanding is that Realm Objects are cached internally)?
  • Are there any problems with the way I'm using Realm ?
  • Are there any better design patterns for my purpose ?

    public struct BookDataLayer: BookDataLayerProvider {
    
    func isBookAvailable(bookIdentifier: String) throws -> Bool {
        let database = try getDatabase()
        return !database.objects(Book).filter("identifier = %@", bookIdentifier).isEmpty
    }
    
    func createOrUpdateBook(bookIdentifier: String, sortIndex: Int) throws {
        let book = Book()
        Book.bookIdentifier = bookIdentifier
        Book.sortIndex = sortIndex
        try create(book, update: true)
    }}
    
    protocol BookDataLayerProvider : DataAccessLayer {
      func isBookAvailable(bookIdentifier: String) throws -> Bool
      func createOrUpdateBook(bookIdentifier: String, sortIndex: Int) throws n} 
    
      extension DataAccessLayer {
    
    func getDatabase() throws -> Realm {
        do {
            let realm = try Realm()
            // Advance the transaction to the most recent state
            realm.refresh()
            return realm
        } catch {
            throw DataAccessError.DatastoreConnectionError
        }
    }
    
    func create(object: Object, update: Bool = false) throws {
        let database = try self.getDatabase()
    
        do {
            database.beginWrite()
            database.add(object, update: update)
            // Commit the write transaction
            // to make this data available to other threads
            try database.commitWrite()
        } catch {
            throw DataAccessError.InsertError
        }
    }}
    
     // Usage
     let bookDataLayer = BookDataLayer()
     bookDataLayer.isBookAvailable("4557788")
    
     bookDataLayer.createOrUpdateBook("45578899", 10)
    
like image 374
Jani Avatar asked Apr 04 '16 07:04

Jani


1 Answers

That's a completely solid design pattern. It's pretty common for developers to abstract the data layer APIs way from their code in case they need to switch it out.

In response to your questions:

  • You're correct. Realm object instances are internally cached, so you can easily call let realm = try! Realm() multiple times with very little overhead.
  • Unless you've found a specific reason, it's probably not necessary to call refresh() on the Realm instance every time you use it. Realm instances on the main thread are automatically refreshed on each iteration of the run loop, so you only need to call refresh() if you're expecting changes on a background thread, or need to access changes before the current run loop has completed.
  • 'Better' design patterns is probably a matter of opinion, but from what I've seen from other codebases, what you've got there is already great! :)
like image 106
TiM Avatar answered Sep 22 '22 15:09

TiM