将枚举用作 Realm 模型的属性

73

我能否在我的模型中使用枚举作为属性?目前我有以下的一个类:

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"
  }
  ....
}

它能正常工作,但我想让kind属性成为枚举,并让Realm在将对象保存到存储时自动调用.rawValue。这在Realm中可行吗?或者已经有相关特性请求了吗?

8个回答

96

你应该重写kindEnum的 setter 和 getter 方法以处理这种情况:

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
    }
  }
}

1
如果您能将此示例添加到您的官方示例中,那将是非常好的。 - Shmidt
这不太好。你为什么不能做到这一点?:https://dev59.com/WV8d5IYBdhLWcg3wXRQX(Martin Krenek的答案)? - Rob
1
你也可以直接在 Realm 中使用 @objc 枚举,但这对于带有 String 关联值的 Swift 枚举是行不通的。 - jpsim
在没有来自Realm的“官方”支持(如果可能的话),这非常有用。谢谢。 - Stephen Watson
2
您可以将kind变量设置为私有,这样您只能使用kindEnum更改其值。 - Nuno Vieira
显示剩余2条评论

53

我将这个模型进一步优化了一下。

enum Thing: String {
    case Thing1
    case Thing2
    case Thing3
}

那么在我的Realm类对象中:

class myClass : Object {
    private dynamic var privateThing = Thing.Thing1.rawValue
    var thing: Thing {
        get { return Thing(rawValue: privateThing)! }
        set { privateThing = newValue.rawValue }
    }
}

这使我们能够编写

myClassInstance.thing = .Thing1
(storing "Thing1" into privateThing),但防止了类型化。
myClassInstance.privateThing = "Thing4"

这不是一个有效的值,因此需要保持数据完整性。


更新:我已编辑原始代码,因为 the = "Thing1" 等是多余的,因为Swift使用了一个字符串字面量等同于其rawValue的情况,这甚至更好,我们可以使用rawValue来设置默认值,这更可靠和更清洁。 :-) - Stephen Watson
谢谢你的补充,我真的很喜欢这个答案。+1 - dehlen

36

Realm 10.0.0 引入 PersistableEnum 协议,可轻松持久化枚举值,无需任何第三方扩展。

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? 
}

3
这应该是2022年的被接受答案。 - Łukasz Duda
这应该是2022年的最佳答案!!! - XY Li
1
这才是真正的正确答案! - AntonioWar

20

由于 Realm 支持 Objective-C 枚举类型,并且它们可以用 Int 表示,因此您可以使用以下代码:

class Checkin: Object {
  dynamic var id: Int = 0
  dynamic var kind: Kind = .checkedIn

  @objc enum Kind: Int {
    case checkedIn
    case enRoute
    case droppedOff
  }
  ....
}

如果你需要将数据解析为/从字符串中获取数据,可以使用自定义的Kind初始化器和一个toString函数。

GitHub上有关于这个问题的讨论。

此方法适用于Swift 3.0和Realm 2.0.2


如果您有一个 Int 枚举,那么这是一个不错的解决方案,但我不知道如何将其适用于 StringKind 被转换为一个不支持自定义初始化程序或存储属性的 Objective-C 枚举。 - Anders Friis
事实上,我还没有找到适用于除了“Int”之外的任何类型的解决方案。 - Diogo T
谢谢您提供这些信息。 我将我的枚举更改为符合 int 类型。 如果您需要一个字符串值,您可以在枚举中创建自己的计算属性,并返回不同情况下的正确值。 - dan
1
请注意,涉及 Int 枚举的任何迁移都需要分配原始值:obj["propertyName"] = Kind.checkedIn.rawValue - Eli Burke

13

Diogo T的解决方案在RealmSwift最近的更新之前是可行的。最终,我们现在必须符合RealmEnum协议才能成为Realm Object的管理属性。

@objc enum MyEnum: Int, RealmEnum {
    ...
}

在某个位置下方添加以下内容:
extension MyEnum: RealmEnum { }

这是与RealmSwift相关的文档


9

简洁易用的解决方案

Realm 版本 >= 10.10.0 开始,您可以这样做

// 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 
}

0

避免强制解包的替代方案 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
        }
    }

0

使用 RealmEnumRealmOptional 的示例

@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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接