How to Save a Struct to Realm in Swift

How to save a struct to realm in swift?

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

How to save struct to Realm, with list of another struct

Instead of making duplicate classes for your every struct, just use Unrealm which will take care everything for you. Just make your structs/enums conform from Realmable protocol. You can save not only an array of Structs but also dictionaries, optional types, atc..

First look:
Sample Image

Here is an example project of how to implement the abstraction layer for the persistency:

link to github

Saving a Realm list made up of an array of struct objects

Why populate 2 separate lists if it needs to be persistent anyway? Just use the list in Realm to populate your table view. Here's a simple example of populating the list using append (just like any array):

class SomeClass: Object {
@objc dynamic var id: String = ""
var someList = List<SomeOtherClass>()

convenience init(id: String) {
self.init()

self.id = id
}
}

@objcMembers class SomeOtherClass: Object {
dynamic var someValue: String = ""

convenience init(value: String) {
self.init()

someValue = value
}
}

func addToList(someOtherClass: SomeOtherClass) {

let realm = try! Realm()

if let someClass = realm.objects(SomeClass.self).last {

do {
try realm.write({
someClass.someList.append(someOtherClass)
})
} catch {
print("something went wrong")
}
}
}

How to save a JSON array to Realm in Swift?

save(todoItem: listArray) doesn't work because save expects an [Object], but listArray is a [TodoListResponse].

What you are missing is the step that converts your codable struct TodoListResponse to the Realm model TodoIItemList. I would write the save method like this:

func save(_ todoListResponses: [TodoListResponse]) {
do{
try realm.write{
for response in todoListResponses {
let object = TodoIItemList()
object.title = response.title
object.completed = response.completed
realm.add(object)
}
}
}catch{
print(error)
}
}

Now save(todoItem: listArray) should work.

If there are many properties that needs to be set in TodoIItemList, you can move the "copying properties" logic to a convenience initialiser of TodoIItemList that initialises a TodoIItemList from a TodoListResponse.

Saving JSON into Realm

There are probably a 100 different ways to map your json to a realm object but let's keep it simple. First I assume your incoming json may be several books so it would look like this

let jsonStringWithKey = """
{
"books":
[{
"author":"Chinua Achebe",
"title":"Things Fall Apart",
"imageLink":"someLink"
},
{
"author":"another author",
"title":"book title",
"imageLink":"another link"
}]
}
"""

So encode it as data

guard let jsonDataWithKey = jsonStringWithKey.data(using: .utf8) else { return }

Then, using JSONSerialization, map it to an array. Keeping in mind the top level object is "books" and AnyObject will be all of the child data

do {
if let json = try JSONSerialization.jsonObject(with: jsonDataWithKey) as? [String: AnyObject] {
if let bookArray = json["books"] as? [[String:AnyObject]] {
for eachBook in bookArray {
let book = Book(withBookDict: eachBook)
try! realm.write {
realm.add(book)
}
}
}
}
} catch {
print("Error deserializing JSON: \(error)")
}

and the Realm object is

class Book: Object, Codable {
@objc dynamic var author = ""
@objc dynamic var title = ""
@objc dynamic var imageLink = ""

convenience init(withBookDict: [String: Any]) {
self.init()

self.author = withBookDict["author"] as? String ?? "No Author"
self.title = withBookDict["title"] as? String ?? "No Title"
self.imageLink = withBookDict["imageLink"] as? String ?? "No link"
}
}

Again, there are a LOT of different ways of handling this so this is kind of the basics that can be expanded on.

As a suggestion, Realm Results are live-updating objects that also have corresponding events. So a neat thing you can do is to make a results object your tableView datasource and add an observer to it.

Results objects work very much like an array.

As books are added, updated or deleted from realm, the results object will reflect those changes and an event will be fired for each one - that makes keeping your tableView updated very simple.

So in your viewController

class ViewController: NSViewController {
var bookResults: Results<PersonClass>? = nil
@IBOutlet weak var bookTableView: NSTableView!
var bookToken: NotificationToken?

self.bookResults = realm.objects(Book.self)

and then

override func viewDidLoad() {
super.viewDidLoad()

self.bookToken = self.bookResults!.observe { changes in
//update the tableView when bookResults change


Related Topics



Leave a reply



Submit