Array of strings is not saved to Realm object using ObjectMapper - ios

This is how I declared imageurls inside My Object:
var imageURLs = List<String>()
and parsing:
func mapping(map: Map) {
imageURLs <- map["image_urls"]
}
and this is what I am trying to parse:
{ "image_urls": ["a"] }
At the end above property is empty. Why?
Using Realm 3.3 so array of primitives should work.

In case you are working with both Realm an ObjectMapper, there is a pretty cool option for you, by using ObjectMapper+Realm, you would be able to map arrays directly to realm lists, as follows:
func mapping(map: Map) {
imageURLs <- (map["image_urls"], ListTransform<String>())
}
Note that by default the object mapper is unable to map arrays as realm lists, which is possible by using the above library.

You can create a variable in the function and map items to an array:
func mapping(map: Map) {
var pathes = [String]()
pathes <- map["image_urls"]
self.imageUrls.add(pathes)
}
Or you could use the extension, which called ObjectMapper+Realm, as written above.

You can map array of String using ObjectMapper like below, this works fine:
import ObjectMapper
import RealmSwift
import ObjectMapper_Realm
public class Items: Object, Mappable {
var images = List<ListImages>()
#objc dynamic var id = 0
required convenience public init?(map : Map){
self.init()
}
public override class func primaryKey() -> String? {
return "id"
}
public func mapping(map: Map) {
var images: [String]? = nil
images <- map["image"]
images?.forEach { image in
let value = ListImages()
value.value = image
self.images.append(value)
}
}
}
class ListImages:Object{
#objc dynamic var value: String = ""
}

I have solved the problem using RealmTypeCastTransform()
In your code just add this
func mapping(map: Map) {
imageURLs <- (map["image_urls"], RealmTypeCastTransform())
}
Now import ObjectMapperAdditions in the beginning of your file

Related

Update single key in realm into array of model in array of model

I am facing on problem, I want to update a single key in my realm model which is in below hierarchy.
Array Model -> Array Model - Key
class OrdersOfDeliveryModel: Object, Mappable {
dynamic var id : String?
dynamic var transportCost : String?
var items = List<ItemsModel>()
required convenience init?(map: Map) {
self.init()
}
override class func primaryKey() -> String? {
return "id"
}
func mapping(map: Map) {
id <- map["id"]
transportCost <- map["transportCost"]
items <- (map["items"], ListTransform<ItemsModel>())
}
}
class ItemsModel : Object, Mappable{
dynamic var orderedQty : Int = 0
dynamic var orderedReceivedQty : String?
required convenience init?(map: Map) {
self.init()
}
override class func primaryKey() -> String? {
return nil
}
func mapping(map: Map) {
var dictWeightageqty = [String:Any]()
dictWeightageqty <- map["weightageQty"]
orderedQty = dictWeightageqty["ordered"] as? Int ?? 0
orderedReceivedQty = dictWeightageqty["received"] as? String
}
}
Please consider this example.
I want to update orderedReceivedQty key which is in ItemsModel but How can I find that key in realm. But my ItemsModel is depending on OrderOfDeliveryModel which can I find with primary key.
I have ways like I delete this whole model using single ID and replace it with new data OR I can get that key and update it.
I dont want to delete whole object and insert new I want to update single key.
Please help me with it.
If you have the OrderOfDeliveryModel object, you can query it for the ItemsModel object you want to update, and then update it in place (if you find it).
let results = myOrders.items.filter("orderedQty == %#", 10)
if (results.count == 1) {
results[0].orderedReceivedQty = 10
}

ObjectMapper toJson empty

I'm trying to deserialize an object into a JSON dictionary with ObjectMapper but the deserializing functions always return empty objects.
class TimeEntryContainer: Mappable {
//MARK: Properties
var entry: TimeEntryObject = TimeEntryObject()
//MARK: Initializers
init() {}
init(_ issue: Issue, hours: Double, activityId: Int) {
self.entry = TimeEntryObject(issue, hours: hours, activityId: activityId)
}
required init?(map: Map) {
mapping(map: map)
}
//MARK: Private Methods
func mapping(map: Map) {
entry <- map["time_entry"]
}
}
class TimeEntryObject {
//MARK: Properties
var issueId = -1
var projectId = ""
var hours = Double()
var activityId = -1
var comments = ""
//MARK: Initializers
init() {}
init(_ issue: Issue, hours: Double, activityId: Int) {
self.issueId = issue.id
self.projectId = issue.project
self.hours = hours
self.activityId = activityId
}
required init?(map: Map) {
mapping(map: map)
}
//MARK: Private functions
func mapping(map: Map) {
issueId <- map["issue_id"]
projectId <- map["project_id"]
hours <- map["hours"]
activityId <- map["activity_id"]
comments <- map["comments"]
}
}
Here's the part where I fill my TimeEntryContainer object
let timeEntry = TimeEntryContainer()
timeEntry.entry.projectId = (issue?.project)!
timeEntry.entry.activityId = activityId
timeEntry.entry.hours = timeEntered
timeEntry.entry.comments = commentEdit.text ?? ""
let deserialized = Mapper().toJSONString(timeEntry)
print("hours: \(deserialized) ")
Even though the values of my timeEntry object are correctly set, the functions Mapper().toJSONString(), Mapper().toJSON() and even timeEntry.toJSON() and timeEntry.toJSONString() return an empty JSON object / dictionary. I can't find where I went wrong
Your TimeEntryObject must be Mappable. You put in the methods but you didn't declare conformance in the class declaration.
class TimeEntryObject: Mappable
I had same issue, in my case I have Mappable protocol implemented. Biut I had not mapped the variables of class which was giving me empty json.
Posting as just another option/ solution. May help someone in case required.

Get and Set different data types in Swift

I am using ObjectMapper. And I know we can specify the keypath like map["name.label"] but I don't want to use keyPath at a moment. Check the below code. I can access name like Author.name?.label.
class Author: Mappable {
var name: LabelDict?
required init?(map: Map) {
}
func mapping(map: Map) {
name <- map["name"]
}
}
class LabelDict: Mappable {
var label: String?
required init?(map: Map) {
}
func mapping(map: Map) {
label <- map["label"]
}
}
How can I set the getter and setter methods of the name property of Author class to set the value as LabelDict class label and when I get the value I get the String directly as Author.name. I can do it by using one different variable but is it possible to do with the same?
You could make your LabelDict adopt CustomStringConvertible protocol.
class LabelDict: Mappable, CustomStringConvertible {
var label: String?
var description: String {
get {
return self.label ?? ""
}
}
required init?(map: Map) {
}
func mapping(map: Map) {
label <- map["label"]
}
}
Then you'd use it like this String(describing: myLabelDictInstance).
-- Clarification
To simply print the label into console you can now use print(Author?.name). If you want to assign it to label for example, you can use someLabel.text = String(describing: Author?.name)

How to map custom Enum/RawRepresentable to dictionary with ObjectMapper?

using the following simplified structure:
class Property: Mappable {
var path: String?
override func mapping(map: Map) {
path <- map["path"]
}
}
class Specification {
enum Name: String {
case Small = "SMALL"
case Medium = "MEDIUM"
}
}
class ItemWithImages: Mappable {
var properties: [Specification.Name : Property]?
override func mapping(map: Map) {
properties <- (map["properties"], EnumTransform<Specification.Name>())
}
}
... with that JSON:
[{"properties: ["SMALL": {"path": "http://..."}, "MEDIUM": {"path": "http://..."}]}]
... produces when using EnumTransform() as Transform the following (reasonable) compile error:
Binary operator '<-' cannot be applied to operands of type '[Specification.Name : Property]?' and '(Map, EnumTransform<Specification.Name>)'
So how does a custom TransformType have to look like, to map that dictionary the right way?
You can find the source of EnumTransform here: https://github.com/Hearst-DD/ObjectMapper/blob/master/ObjectMapper/Transforms/EnumTransform.swift
Thanks!
TransformTypes are IMHO primary designed to transform values and not keys. And your example is a little bit complicated because even value is not just basic type.
What do you think about this little hack?
struct ItemWithImages: Mappable {
var properties: [Specification.Name : Property]?
init?(_ map: Map) {
}
mutating func mapping(map: Map) {
let stringProperties: [String: Property]?
// map local variable
stringProperties <- map["properties"]
// post process local variable
if let stringProperties = stringProperties {
properties = [:]
for (key, value) in stringProperties {
if let name = Specification.Name(rawValue: key) {
properties?[name] = value
}
}
}
}
}
We should use DictionaryTransform instead of EnumTransform. We are transforming type of Dictionary [String:Any] to [Key:Value]. In our case type is [Specification.Name: Property].
Key need to conforms protocols like Hashable, RawRepresentable, and Key.RawValue should be String.
And Value Should be conforms Mappable Protocol.
class Property: Mappable {
var path: String?
override func mapping(map: Map) {
path <- map["path"]
}
}
class Specification {
enum Name: String {
case Small = "SMALL"
case Medium = "MEDIUM"
}
}
class ItemWithImages: Mappable {
var properties: [Specification.Name : Property]?
override func mapping(map: Map) {
properties <- (map["properties"], DictionaryTransform<Specification.Name,Property>())
}
}

Nested array of double in realm (swift)

I have this JSON:
{
"location": {
"position": {
"type": "Point",
"coordinates": [
45.579553,
11.751805
]
}
}
}
Which belongs to another JSON object.
Trying to map it with Realm and ObjectMapper, I am findind difficulties mapping the coordinates property which is an array of double.
That's what reading the documentation and S.O. seems to have sense:
import Foundation
import RealmSwift
import ObjectMapper
class Coordinate:Object, Mappable{
dynamic var latitude:Double = 0.0
dynamic var longitude:Double = 0.0
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
latitude <- map[""]
longitude <- map[""]
}
}
class Position: Object, Mappable{
var type:String = ""
var coordinates:Coordinate?
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
type <- map["type"]
coordinates <- map["coordinates"]
}
}
class Location: Object, Mappable{
dynamic var id = ""
dynamic var position:Position?
dynamic var desc = ""
override static func indexedProperties()->[String]{
return["id"]
}
override class func primaryKey() -> String? {
return "id"
}
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
id <- map["id"]
position <- map["position"]
}
}
However I'm stuck in understanding how to map the "coordinates" object. Please note that this problem has nothing to do with ObjectMapper itself, it's more of a question on how to assign an array of Double to a property in a Realm model.
I was able to solve this following the indications in this issue:
https://github.com/realm/realm-cocoa/issues/1120 (credits #jazz-mobility)
class DoubleObject:Object{
dynamic var value:Double = 0.0
}
class Position: Object, Mappable{
var type:String = ""
var coordinates = List<DoubleObject>()
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
type <- map["type"]
var coordinates:[Double]? = nil
coordinates <- map["coordinates"]
coordinates?.forEach { coordinate in
let c = DoubleObject()
c.value = coordinate
self.coordinates.append(c)
}
}
}
You can now simply use List<Double>() without it storing an object.
More information can be found here: https://academy.realm.io/posts/realm-list-new-superpowers-array-primitives/
#objcMembers class RealmObject: Object, Mappable {
dynamic var listValues = List<MyRealmObject>()
required convenience init?(map: Map) {
self.init()
}
// Mappable
func mapping(map: Map) {
listValues <- (map["listValues"], RealmlistObjectTransform())
}
}
#objcMembers class MyRealmObject: Object, Mappable {
required convenience init?(map: Map) {
self.init()
}
// Mappable
func mapping(map: Map) {
}
}
class RealmlistObjectTransform: TransformType {
typealias Object = List<MyRealmObject> // My Realm Object here
typealias JSON = [[String: Any]] // Dictionary here
func transformFromJSON(_ value: Any?) -> List<MyRealmObject>? {
let list = List<MyRealmObject>()
if let actors = value as? [[String: Any]] {
let objects = Array<MyRealmObject>(JSONArray: actors)
list.append(objectsIn: objects)
}
return list
}
func transformToJSON(_ value: List<MyRealmObject>?) -> [[String: Any]]? {
if let actors = value?.sorted(byKeyPath: "").toArray(ofType: MyRealmObject.self).toJSON() {
return actors
}
return nil
}
}

Resources