ObjectMapper toJson empty - ios

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.

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
}

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>())
}
}

How to map this JSON using ObjectMapper?

I am getting this JSON in response from a webservice. I am able to understand the structure of the file.
{"response":200,"message":"fetch successfully","data":[
{"id":1,"question":"Are you currently exercising regularly?","choices":{"too_lazy":"Too lazy","times_1_3_week":"1-3 times a week","i_love_it":"I just love it!"},"answer_select":"single"},
{"id":2,"question":"Are you active member of Gym?","choices":{"yes":"Yes","no":"No"},"answer_select":"single"}]
}
and this is what I have so far
import Foundation
import UIKit
import ObjectMapper
class YASUserQuestion: Mappable {
var question: String
var id: Int
var choices: [YASExercisingQuestionChoices]
required init?(_ map: Map) {
question = ""
id = 0
choices = []
}
func mapping(map: Map) {
question <- map["question"]
id <- map["id"]
choices <- map["choices"]
}
}
class YASExercisingQuestionChoices: Mappable {
var tooLazy: String
var times_1_3_Week: String
var ILoveIt: String
required init?(_ map: Map) {
tooLazy = ""
times_1_3_Week = ""
ILoveIt = ""
}
func mapping(map: Map) {
tooLazy <- map["too_lazy"]
times_1_3_Week <- map["times_1_3_week"]
ILoveIt <- map["i_love_it"]
}
}
class YASGymMemberQuestionChoices: Mappable {
var yes: String
var no: String
required init?(_ map: Map) {
yes = ""
no = ""
}
func mapping(map: Map) {
yes <- map["yes"]
no <- map["no"]
}
}
I am not sure how to map this JSON response so can you please guide me How can I map this JSON ???
This will be your classes structure. After making these classes, next you just have map your JSON using ObjectMapper.
import UIKit
import ObjectMapper
class UserResponse: NSObject,Mappable {
var message: String?
var response: String?
var data: [DataClass]?
override init() {
super.init()
}
convenience required init?(map: Map) {
self.init()
}
func mapping(map: Map) {
message <- map["message"]
response <- map["response"]
data <- map["data"]
}
}
class DataClass: NSObject,Mappable {
var answer_select: String?
var ID: String?
var question: String?
var choices: [ChoicesClass]?
override init() {
super.init()
}
convenience required init?(map: Map) {
self.init()
}
func mapping(map: Map) {
answer_select <- map["answer_select"]
ID <- map["id"]
question <- map["question"]
choices <- map["choices"]
}
}
class ChoicesClass: NSObject,Mappable {
var i_love_it: String?
var times_1_3_week: String?
var too_lazy: String?
override init() {
super.init()
}
convenience required init?(map: Map) {
self.init()
}
func mapping(map: Map) {
i_love_it <- map["i_love_it"]
times_1_3_week <- map["times_1_3_week"]
too_lazy <- map["too_lazy"]
}
}

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
}
}

fatal error: use of unimplemented initializer 'init(realm:schema:)' for class MyApp.User

Im getting this error when i try to load a user from the database.
dispatch_async(dispatch_queue_create("background", nil)) {
let realm = try! Realm()
let users = realm.objects(User)
print(users)
}
class User: Object, Mappable {
dynamic var id = 0
dynamic var name = ""
dynamic var userName = ""
required init() {
super.init()
}
// MARK: Mappable
func mapping(map: Map) {
id <- map["Id"]
name <- map["Name"]
userName <- map["UserName"]
}
required init?(_ map: Map) { super.init() }
}
I tried implemeting that init method but i get (Use of undeclared identifier RLMObjectSchema):
Any hints?
When I use realm, I will only use convenience init.
In your case
class User: Object, Mappable {
dynamic var id = 0
dynamic var name = ""
dynamic var userName = ""
// MARK: Mappable
func mapping(map: Map) {
id <- map["Id"]
name <- map["Name"]
userName <- map["UserName"]
}
convenience init?(_ map: Map) { self.init() }
}
If you want implement designate init, you should implement
init(realm: RLMRealm, schema: RLMObjectSchema) {
super.init(realm: realm, schema: schema)
}
When you implement designate init(), swift will not inherit other designate init methods which are required by realm.

Resources