How to Encode Realm's List<> Type

How to encode Realm's List type

To make a Realm object model class with a property of type List conform to Encodable, you can simply convert the List to an Array in the encode(to:) method, which can be encoded automatically.

extension User: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.username, forKey: .username)
let dogsArray = Array(self.dogs)
try container.encode(dogsArray, forKey: .dogs)
}
}

Test classes I used (slightly different from the ones in your question, but I already had these on hand and the methods in question will be almost identical regardless of the variable names):

class Dog: Object,Codable {
@objc dynamic var id:Int = 0
@objc dynamic var name:String = ""
}

class User: Object, Decodable {
@objc dynamic var id:Int = 0
@objc dynamic var username:String = ""
@objc dynamic var email:String = ""
let dogs = List<Dog>()

private enum CodingKeys: String, CodingKey {
case id, username, email, dogs
}

required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
username = try container.decode(String.self, forKey: .username)
email = try container.decode(String.self, forKey: .email)
let dogsArray = try container.decode([Dog].self, forKey: .dogs)
dogs.append(objectsIn: dogsArray)
}
}

Test the encoding/decoding:

let userJSON = """
{
"id":1,
"username":"John",
"email":"example@ex.com",
"dogs":[
{"id":2,"name":"King"},
{"id":3,"name":"Kong"}
]
}
"""

do {
let decodedUser = try JSONDecoder().decode(User.self, from: userJSON.data(using: .utf8)!)
let encodedUser = try JSONEncoder().encode(decodedUser)
print(String(data: encodedUser, encoding: .utf8)!)
} catch {
print(error)
}

Output:

{"username":"John","dogs":[{"id":2,"name":"King"},{"id":3,"name":"Kong"}]}

How to use List type with Codable? (RealmSwift)

You are almost there. Inside the initializer, you can initialize the list using the decoded array. Basically, change

tags = try container.decode(List<Tag>.self, forKey: .tags)   // this is problem.

to

let tagsArray = try container.decode([Tag].self, forKey: .tags)   
tags = List(tagsArray) // Now you are good

As pointed out in the comments the List constructor no longer works like this

You now want:

tags.append(objectsIn: tagsArray)

How to convert an array to List in Realm?

Note that your problem is not about converting List to array, but rather converting an array to List. You already know how to do the former: Array(someList), but since you are assigning an array (movie.genreIDs ?? []) to a List property (movieRealm.genreIDs), you need to convert an array to a List.

But wait! movieRealm.genreIDs is a let constant, so you can't assign to it anyway. Your real problem is that you haven't declared the genreIDs property correctly.

If you follow the docs on how to declare a property of a List type:

class CachedMovies: Object {
// genreIDs should not be optional
let genreIDs = List<Int>()
}

You'll see that you don't need to convert arrays to List. You can just add the contents of the array to the List, since the list is not nil:

movieRealm.genreIDs.append(objectsIn: move.genreIDs ?? [])

Note that if you actually want an optional list property (a property which can be nil, empty, or have elements), Realm doesn't support that.

Realm Swift - Convert an array of results into an array of Ints

You can simply use Array(realm.objects(RealmType.self)), which will convert the Results<RealmType> instance into an Array<RealmType>.

However, there are other serious flaws with your code. First of all, neither of the last two lines will compile, since firstly realm.objects() accepts a generic input argument of type Object.Type and Data doesn't inherit from Object. You can't directly store Data objects in Realm, you can only store Data as a property of a Realm Object subclass.

Secondly, myArray[results] is simply wrong, since results is supposed to be of type Results<RealmType>, which is a collection, so using it to index an Array cannot work (especially whose Element type is different).

Realm: Results T als List T

We can use extensions to make life easier :

extension Realm {
func list<T: Object>(_ type: T.Type) -> List<T> {
let objects = self.objects(type)
let list = objects.reduce(List<T>()) { list, element -> List<T> in
list.append(element)
return list
}

return list
}
}

Usage:

let objects = realm.list(YourObject.self)

How to convert RealmResults Object to List Object

To eagerly read every element from the Realm (and therefore make all elements in the list become unmanaged, you can do):

 List<StepEntry> arrayListOfUnmanagedObjects = realm.copyFromRealm(realmResults);

But you generally have absolutely no reason to do that unless you want to serialize the objects with GSON (specifically, because it reads field data with reflection rather than with getters), because Realm was designed in such a way that the list exposes a change listener, allowing you to keep your UI up to date just by observing changes made to the database.

how to convert RealmSwift List to Results?

Both List and Results (as well as LinkingObjects) can be converted into an AnyRealmCollection type. I think this is probably the best way to standardize all of Realm's array-type types:

var dataSource:AnyRealmCollection!
let aRealmObject = realm.objectForPrimaryKey(SomeObject.self, key: objectId)
dataSource = AnyRealmCollection(aRealmObject.someList)

RealmSwift: Convert Results to Swift Array

I found a solution. Created extension on Results.

extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for i in 0 ..< count {
if let result = self[i] as? T {
array.append(result)
}
}

return array
}
}

and using like

class func getSomeObject() -> [SomeObject]? {
let objects = Realm().objects(SomeObject).toArray(SomeObject) as [SomeObject]

return objects.count > 0 ? objects : nil
}


Related Topics



Leave a reply



Submit