Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save a struct to realm in swift?

Tags:

swift

realm

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.

like image 282
beseder Avatar asked Jan 28 '16 11:01

beseder


4 Answers

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

like image 183
Ludovic Avatar answered Oct 17 '22 18:10

Ludovic


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.

like image 26
Adam Fish Avatar answered Oct 17 '22 19:10

Adam Fish


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)
}
like image 14
Husam Avatar answered Oct 17 '22 18:10

Husam


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.

enter image description here

like image 5
arturdev Avatar answered Oct 17 '22 18:10

arturdev