It is easy to use Realm with classes by inheriting from Object
. But how would I save a struct
containing several fields to realm in Swift? E.g.
struct DataModel {
var id = 0
var test = "test"
}
I know the documentation is clear about supported types. But maybe there is nice workaround or - even better - someone from realm could write about future plans about structs.
To save a struct
in Realm, means copying the data into a Realm Object
. The reason why Realm Objects
are classes and not structs
is because they are not inert values, but auto-updating objects that represent the persisted data in Realm. This has practical benefits, such as the fact that a Realm Object
's data is lazy loaded.
You can take advantage of Realm's approach by responding to the change notifications from a Realm instance. For example if your UITableView
data source is based off an array property on a Realm Object
, as long as you have an instance of that object, you are guaranteed that after the notification it represents the correct values. Used properly this can simplify your code versus having multiple copies of values as structs.
I' suggest you to use protocols, to achive what you want.
1) Create your Struct
struct Character {
public let identifier: Int
public let name: String
public let realName: String
}
2) Create your Realm Object
final class CharacterObject: Object {
dynamic var identifier = 0
dynamic var name = ""
dynamic var realName = ""
override static func primaryKey() -> String? {
return "identifier"
}
}
3) Use protocols to transform our struct to Realm Object
public protocol Persistable {
associatedtype ManagedObject: RealmSwift.Object
init(managedObject: ManagedObject)
func managedObject() -> ManagedObject
}
4) Make your struct persistable
extension Character: Persistable {
public init(managedObject: CharacterObject) {
identifier = managedObject.identifier
name = managedObject.name
realName = managedObject.realName
}
public func managedObject() -> CharacterObject {
let character = CharacterObject()
character.identifier = identifier
character.name = name
character.realName = realName
return character
}
}
With these tools in place, we are ready to implement the insertion methods of our persistence layer.
5) Exemple to write datas
public final class WriteTransaction {
private let realm: Realm
internal init(realm: Realm) {
self.realm = realm
}
public func add<T: Persistable>(_ value: T, update: Bool) {
realm.add(value.managedObject(), update: update)
}
}
// Implement the Container
public final class Container {
private let realm: Realm
public convenience init() throws {
try self.init(realm: Realm())
}
internal init(realm: Realm) {
self.realm = realm
}
public func write(_ block: (WriteTransaction) throws -> Void)
throws {
let transaction = WriteTransaction(realm: realm)
try realm.write {
try block(transaction)
}
}
}
5) Use the magic!
let character = Character(
identifier: 1000,
name: "Spiderman",
realName: "Peter Parker"
)
let container = try! Container()
try! container.write { transaction in
transaction.add(character)
}
Amazing source : Using Realm with Value Types & My Article
Swift 4 shortest answer
Save structs as Data in Realm
struct MyStruct : Codable { // Variables here }
class MyRealObject : Object {
@objc private dynamic var structData:Data? = nil
var myStruct : MyStruct? {
get {
if let data = structData {
return try? JSONDecoder().decode(MyStruct.self, from: data)
}
return nil
}
set {
structData = try? JSONEncoder().encode(newValue)
}
}
}
Use the magic
let realm = try! Realm()
try! realm.write {
let myReal = MyRealObject()
myReal.myStruct = MyStruct(....)
realm.add(myReal)
}
You can do what suggests Ludovic, or you can automate that process and get rid of that boilerplate code for each of your structs by using Unrealm.