Using enum as property of Realm model
IosEnumsRealmIos Problem Overview
Is it possible to use an Enum as a property for my model? I currently have a class like this:
class Checkin: RLMObject {
dynamic var id: Int = 0
dynamic var kind: String = "checked_in"
var kindEnum: Kind = .CheckedIn {
willSet { self.kind = newValue.rawValue }
}
enum Kind: String {
case CheckedIn = "checked_in"
case EnRoute = "en_route"
case DroppedOff = "dropped_off"
}
....
}
It works okay, but I'd like to be able to have the kind
property be the Enum and have Realm automatically call .rawValue
on the property when it is saving an object to the store. Is this possible in Realm or is there a feature request already out there for it?
Ios Solutions
Solution 1 - Ios
You should override your kindEnum
's setter and getter for this case:
enum Kind: String {
case CheckedIn
case EnRoute
case DroppedOff
}
class Checkin: Object {
@objc dynamic var id = 0
var kind = Kind.CheckedIn.rawValue
var kindEnum: Kind {
get {
return Kind(rawValue: kind)!
}
set {
kind = newValue.rawValue
}
}
}
Solution 2 - Ios
I've refined this model a little further.
enum Thing: String {
case Thing1
case Thing2
case Thing3
}
then in my Realm class object:
class myClass : Object {
private dynamic var privateThing = Thing.Thing1.rawValue
var thing: Thing {
get { return Thing(rawValue: privateThing)! }
set { privateThing = newValue.rawValue }
}
}
This allows us to write
myClassInstance.thing = .Thing1
(storing "Thing1" into privateThing), but prevents typing of
myClassInstance.privateThing = "Thing4"
which is not a valid value so preserving data integrity.
Solution 3 - Ios
Since Realm support Objective-C enums and they are representable by Int
you can use this:
class Checkin: Object {
dynamic var id: Int = 0
dynamic var kind: Kind = .checkedIn
@objc enum Kind: Int {
case checkedIn
case enRoute
case droppedOff
}
....
}
If you need to parse to/from String
you can use a custom initializer for Kind
and an toString
function.
There is a discussion about this in GitHub
This works with Swift 3.0
and Realm 2.0.2
Solution 4 - Ios
Diogo T's solution worked before recent updates of RealmSwift. Eventually we now have to conform to RealmEnum
protocol to be able to be a managed property of Realm Object
.
@objc enum MyEnum: Int, RealmEnum {
...
}
Or add below in some place:
extension MyEnum: RealmEnum { }
Solution 5 - Ios
Realm 10.0.0 introduces PersistableEnum
Protocol that makes it easy to persist enum values without any third-party extensions.
enum TaskStatusEnum: String, PersistableEnum {
case notStarted
case inProgress
case complete
}
// To use the enum:
class Task: Object {
// Required enum property
@Persisted var status = TaskStatusEnum.notStarted
// Optional enum property
@Persisted var optionalTaskStatusEnumProperty: TaskStatusEnum?
}
Solution 6 - Ios
Clean & Easy solution
From Realm version >= 10.10.0
you can do this:
// Define the enum
enum StatusEnum: String, PersistableEnum {
case notStarted
case inProgress
case complete
}
// To use the enum:
class Task: Object {
@Persisted var status = StatusEnum.notStarted
}
Solution 7 - Ios
Example with RealmEnum
and RealmOptional
@objc enum MyEnum: Int, RealmEnum {
case first
case second
}
final class MyEntry: Object {
//It should be let
let someVariable = RealmOptional<CRUD>()
}
//using
myEntry.someVariable.value = MyEnum.first
Solution 8 - Ios
Alternate solution to avoid the force un-wrap get { return Thing(rawValue: privateThing)! }
enum Kind: String, CaseIterable {
case CheckedIn
case EnRoute
case DroppedOff
}
@objc dynamic var kindRaw = Kind.CheckedIn.rawValue
var kind: Kind {
get {
for kind in Kind.allCases where kindRaw == kind.rawValue {
return kind
}
return .CheckedIn //default
}
set {
kindRaw = newValue.rawValue
}
}