Использование enum как свойства модели Realm

Можно ли использовать Enum как свойство для моей модели? Сейчас у меня есть такой класс:

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 было Enum, а Realm автоматически вызывала .rawValue для свойства при сохранении объекта в хранилище. Возможно ли это в Realm, или для этого уже есть запрос функции?


person Dave Long    schedule 18.03.2015    source источник


Ответы (6)


В этом случае вы должны переопределить ваши сеттеры и геттеры kindEnum:

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
    }
  }
}
person jpsim    schedule 19.03.2015
comment
Было бы здорово, если бы вы могли добавить этот образец к своим официальным примерам. - person Shmidt; 18.05.2015
comment
Это не здорово. Почему вы не можете этого сделать ?: stackoverflow.com/questions/26900302/ (ответ Мартина Кренека)? - person Rob; 21.10.2015
comment
Вы также можете использовать @objc перечисления непосредственно с Realm, но это не будет работать для перечислений Swift с String связанными значениями. - person jpsim; 21.10.2015
comment
В отсутствие официальной поддержки Realm (если это вообще возможно) это очень полезно. Спасибо. - person Stephen Watson; 02.11.2015
comment
Вы можете установить переменную kind как частную, поэтому вы можете изменить ее значение только с помощью kindEnum. - person Nuno Vieira; 22.08.2016
comment
просто предложение: поскольку я использую перечисление больше, чем необработанное значение в моем коде, я назвал их kindRaw и kind - person alternatiph; 12.12.2016
comment
Выглядит действительно ужасно - person imike; 28.04.2018

Я немного доработал эту модель.

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

(сохраняет Thing1 в privateThing), но предотвращает ввод

myClassInstance.privateThing = "Thing4"

что не является допустимым значением, поэтому сохраняется целостность данных.

person Stephen Watson    schedule 02.11.2015
comment
Обновление: я отредактировал свой исходный код, потому что the = Thing1 и т. Д. Является избыточным, поскольку Swift использует строковый буквальный эквивалент case для его rawValue, что даже лучше, и мы можем использовать rawValue, чтобы установить значение по умолчанию, которое более надежно и чище. :-) - person Stephen Watson; 02.11.2015
comment
Спасибо за это дополнение, мне очень нравится этот ответ. +1 - person dehlen; 27.05.2016

Поскольку 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
  }
  ....
}

Если вам нужно выполнить синтаксический анализ в / из String, вы можете использовать собственный инициализатор для Kind и toString функции.

Это обсуждается в GitHub

Это работает со Swift 3.0 и Realm 2.0.2

person Diogo T    schedule 26.12.2016
comment
Хорошее решение, если у вас есть Int перечисление, но оно не видит, как оно может работать с String. Kind преобразуется в перечисление Objective-C, которое не поддерживает настраиваемые инициализаторы или сохраненные свойства ..? - person Anders Friis; 06.02.2017
comment
В самом деле, я не нашел решения, которое работает с любым типом, кроме Int - person Diogo T; 07.02.2017
comment
Спасибо за эту информацию. Я изменил свое перечисление, чтобы оно соответствовало int. Если вам нужно строковое значение, вы можете создать собственное вычисляемое свойство в перечислении и вернуть правильное значение для разных случаев. - person dan; 02.04.2018
comment
Обратите внимание, что любые миграции, которые вы выполняете с использованием перечислений Int, должны будут назначать необработанное значение: obj [propertyName] = Kind.checkedIn.rawValue - person Eli Burke; 20.03.2019

Решение Diogo T работало до недавних обновлений RealmSwift. В конце концов, теперь мы должны соответствовать протоколу RealmEnum, чтобы иметь возможность быть управляемым свойством Realm Object.

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

Или добавьте ниже где-нибудь:

extension MyEnum: RealmEnum { }

документация по RealmSwift для него

person Pei    schedule 04.02.2020

Пример с RealmEnum и 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
person yoAlex5    schedule 14.10.2020

Альтернативное решение, чтобы избежать принудительного разворачивания 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
        }
    }
person railwayparade    schedule 12.02.2021