RealmSwift - How to override hash function when migrating pre-existing Class to Realm

Viewed 596

I have an existing Movie class that I now wish to store using the RealmSwift Framework. Previously I had conformed Movie to the Hashable protocol (for performing Set() operations on arrays of Movies), but this is made redundant by Realm's requirement to conform to its Object protocol.

However, now I get an error with my (re)declaration of the hash(into hasher: _) function (as needed by Hashable):

Overriding declarations in extensions is not supported
Overriding non-open instance method outside of its defining module
1. Overridden declaration is here (ObjectiveC.NSObject)

Screenshot of the error messages from declaring func hash(...), as previously required to conform to Hashable


I've checked many issue reports on the Realm git repo to no success (and some have been incorrectly marked as closed, I believe):

I've tried with and without a declared primaryKey, as well as putting a dummy initial (guaranteed unique) id via dynamic var id = UUID().uuidString - although it should be noted that Movie() is NEVER called - I always use the (now convenience, with this Realm refactor) convenience init(title: String, id: String, cast: String ) initialiser.

Some suggestions include overriding a hash or hashValue variable, but the latter has been made redundant by the former (and the former still doesn't work for me - in this example case, I am just using the id parameter for the Movie's hash/hashValue:

override var hash: Int {
  return id.hashValue
}

override var hashValue: Int {
  return id.hashValue
}

My Movie code is as follows (with the fatal error on func hash(into hasher: inout Hasher) { as shown in the above screenshot):

import Foundation
import UIKit
import EventKit
import RealmSwift

@objcMembers class Movie: Object {
 dynamic var title: String = ""
 dynamic var id: String = ""
 dynamic var cast: String  = ""

 convenience init(title: String, id: String, cast: String ) {
    self.init()
    self.title = title
    self.id = id
    self.cast = cast
 }

 override static func primaryKey() -> String? {
    return "id"
 }

 func hash(into hasher: inout Hasher) {
    hasher.combine(title)
    hasher.combine(id)
    hasher.combine(cast)
 }
}

An example of the Set() arithmetic that I wish to perform on arrays of Movies, [Movie]. In this example I am checking if subSetOfMovies is a sub-set of allMovies, if-not then add it to the list of allMovies:

 if !Set<Movie>(subSetOfMovies).isSubset(of: Set(allMovies)) {
   allMovies.append(contentsOf: subSetOfMovies)
 } else {
   print("subSetOfMovies is a subset of allMovies, thus it is not added.")
 }

Note: I wish to use Set arithmetic because it is very fast. For long lists of movies I do not wish to check that each movie, individually (say with a for-loop), is not included in the allMovies array.


Basically, I want to be able to manually reconform my Movie class to Hashable so that I can perform set arithmetic on it (as I did before I started to implement RealmSwift to my Movie Model). However, as things currently stand, it seems that I can't with Realm - unless I'm missing something obvious...

0 Answers
Related