AlamofireObjectMapper how to map object? - ios

This is the reponse which i got from api
{
Message = "email verification link has been sent to your email. please verify your account.";
Result = {
"V002_vendors_type" = "<null>";
"V003_pharmacy" = (
);
"V010_subscription" = "<null>";
"attempt_date" = "<null>";
created = "2016-04-27T12:26:04.5809108+00:00";
email = "i9#gmail.com";
"first_name" = jack;
id = 10180;
"is_lock" = 0;
"last_name" = "<null>";
mobile = 9999999999;
password = e10adc3949ba59abbe56e057f20f883e;
"profile_Image" = "<null>";
status = PV;
subscription = 1;
updated = "2016-04-27T12:26:04.5809108+00:00";
"vendor_type_id" = 1;
};
Status = 1;}
now i am mapping this response by alamofireObjectMapper
here is my code
func pharmacySignUp()
{
let url = "http://\(basicURL)vendor_signup"
let param :[String : AnyObject] =
[
"email" : txtemail.text!,
"password" : txtpassword.text!,
"mobile" : txtmobile.text!,
"first_name" : txtname.text!
]
Alamofire.request(.POST, url, parameters: param, encoding: .JSON).responseObject { (response:Response<signupVarificationCode, NSError>) in
print(response.result.value)
let signupVarificationCode = response.result.value
print(signupVarificationCode)
print(signupVarificationCode!.Message)
print(signupVarificationCode?.Status)
print(signupVarificationCode?.result)
if let threedayForecast = signupVarificationCode?.result {
for ResultNew in threedayForecast {
print(ResultNew)
}
}
}
and these are my class in which i am saving values
class signupVarificationCode: Mappable {
var Message : String?
var Status : String?
var result:[String:AnyObject]?
required init?(_ map: Map){
}
func mapping(map: Map) {
Message <- map["Message"]
Status <- map["Status"]
result <- map["Result"]
}
}
class Resultnew: Mappable
{
var lastName : String?
var isLock : String?
var mobile : String?
var id: String?
var attemptDate : String?
var Created : String?
var Updated : String?
var Subscription: String?
var vendor_type : String?
var profileimage : String?
var pharmacy : String?
var vsbuscription : String?
var email: String?
var status : String?
var vendor_typeId : String?
var FirstName : String?
var Password: String?
required init?(_ map: Map){
}
func mapping(map: Map) {
lastName <- map["last_name"]
mobile <- map["mobile"]
id <- map["id"]
isLock <- map["is_lock"]
attemptDate <- map["attempt_date"]
Created <- map["created"]
Updated <- map["updated"]
Subscription <- map["subscription"]
vendor_type <- map["V002_vendors_type"]
profileimage <- map["profile_Image"]
pharmacy <- map["V003_pharmacy"]
vsbuscription <- map["V010_subscription"]
email <- map["email"]
status <- map["status"]
vendor_typeId <- map["vendor_type_id"]
FirstName <- map["first_name"]
Password <- map["password"]
}
}
Here i am getting values in my function as
for ResultNew in threedayForecast {
print(ResultNew)
}
but these vales are coming like this
("last_name", <null>)
("mobile", 123456)
("is_lock", 0)
("attempt_date", <null>)
("created", 2016-04-27T12:32:20.6046072+00:00)
("updated", 2016-04-27T12:32:20.6046072+00:00)
("subscription", 1)
("V002_vendors_type", <null>)
("profile_Image", <null>)
("V003_pharmacy", [])
("V010_subscription", <null>)
("email", i10#gmail.com)
("status", PV)
("vendor_type_id", 1)
("first_name", jack)
("id", 10182)
("password", e10adc3949ba59abbe56e057f20f883e)
but i cannot access is like this
print(ResultNew.mobile)
so how acn i access perticular value which i want to access.like i want to only password among these so how can do this?

You specified that the result should be a dictionary ([String:AnyObject]) so you got a dictionary. Try changing it to this :
var Message : String?
var Status : String?
var result:Resultnew? // <-- this line

Related

How to map variable number of nested objects in object mapper swift

I have a JSON response (bellow) and I need to parse this -
[
{
"id":123,
"name":"Fahim Rahman",
"age":25,
"friends":[
{
"firstName": "Imtiaz",
"lastName": "Khan",
"avatar_url": null
}
],
"groups":{
"xcet":{
"name":"xcek cert etsh tnhg",
"createdDate":"2022-10-31T10:00:48Z"
},
"juyt":{
"name":"jfd uyt you to",
"createdDate":"2021-09-13T10:00:00Z"
},
"some random key":{
"name": "some name",
"createdDate":"2026-03-27T10:00:00Z"
}
}
}
]
To parse this in my code I've created this model. I can not able to parse the groups as that is not a list but an object -
import ObjectMapper
class Person: BaseObject {
#objc dynamic var ID: Int = -1
#objc dynamic var name: String = ""
#objc dynamic var age: Int = -1
var friendsList = List<Friends>()
override func mapping(map: ObjectMapper.Map) {
ID <- map["id"]
name <- map["name"]
age <- map["age"]
friendsList <- map["friends"]
}
}
class Friends: BaseObject {
#objc dynamic var firstName: String = ""
#objc dynamic var lastName: String = ""
#objc dynamic var avatarURL: String = ""
override func mapping(map: ObjectMapper.Map) {
firstName <- map["firstName"]
lastName <- map["name"]
avatarURL <- map["avatar_url"]
}
}
I know it's a bad JSON. The groups should be on the list instead of the nested objects but unfortunately, I'm getting this response.
Here in the response of groups, the number of nested objects is dynamic and the key of the nested object is also dynamic. Thus I can not able to parse this as friends attribute.
So my question is, how can I map the "groups"?
Before mapping groups, we need a class that can hold each Group alongside its key (i.e. xct)
For example
Class Groups: BaseObject {
#objc dynamic var key: String = ""
#objc dynamic var value: GroupsItem?
convenience init(key: String, value: GroupsItem) {
self.init()
self.key = key
self.value = value
}
}
Class GroupsItem: BaseObject {
#objc dynamic var name: String?
#objc dynamic var createdDate: String?
...
}
Then inside your Person class you can map this as -
private func mapGroupsItems(map: ObjectMapper.Map) -> List<GroupsItem> {
var rowsDictionary: [String: Groups]?
rowsDictionary <- map["groups"]
let rows = List<GroupsItem>()
if let dictionary = rowsDictionary {
for (key, value) in dictionary {
rows.append(GroupsItem(key: key, value: value))
}
}
return rows
}
dont forget to call this method from mapping -
override public func mapping(map: ObjectMapper.Map) {
...
groups = mapGroupsItems(map: map)
}
try this approach, using a custom init(from decoder: Decoder) for Groups, works well for me. Use a similar approach for non-SwiftUI systems.
struct ContentView: View {
#State var people: [Person] = []
var body: some View {
ForEach(people) { person in
Text(person.name)
ForEach(Array(person.groups.data.keys), id: \.self) { key in
Text(key).foregroundColor(.red)
Text(person.groups.data[key]?.name ?? "no name").foregroundColor(.blue)
Text(person.groups.data[key]?.createdDate ?? "no date").foregroundColor(.blue)
}
}
.onAppear {
let json = """
[
{
"id":123,
"name":"Fahim Rahman",
"age":25,
"friends":[
{
"firstName": "Imtiaz",
"lastName": "Khan",
"avatar_url": null
}
],
"groups":{
"xcet":{
"name":"xcek cert etsh tnhg",
"createdDate":"2022-10-31T10:00:48Z"
},
"juyt":{
"name":"jfd uyt you to",
"createdDate":"2021-09-13T10:00:00Z"
},
"some random key":{
"name": "some name",
"createdDate":"2026-03-27T10:00:00Z"
}
}
}
]
"""
if let data = json.data(using: .utf8) {
do {
self.people = try JSONDecoder().decode([Person].self, from: data)
print("---> people: \(people)")
} catch {
print("decode error: \(error)")
}
}
}
}
}
struct Person: Identifiable, Codable {
let id: Int
var name: String
var age: Int
var friends: [Friend]
var groups: Groups
}
struct Friend: Codable {
var firstName, lastName: String
var avatarURL: String?
enum CodingKeys: String, CodingKey {
case firstName, lastName
case avatarURL = "avatar_url"
}
}
struct Info: Codable {
var name: String
var createdDate: String
}
struct Groups: Identifiable, Codable {
let id = UUID()
var data: [String:Info] = [:]
init(from decoder: Decoder) throws {
do {
let container = try decoder.singleValueContainer()
self.data = try container.decode([String:Info].self)
} catch {
print(error)
}
}
}
Your Model classes structure will be
// MARK: - Welcome7Element
struct Welcome7Element {
let id: Int
let name: String
let age: Int
let friends: [Friend]
let groups: Groups
}
// MARK: - Friend
struct Friend {
let firstName, lastName: String
let avatarURL: NSNull
}
// MARK: - Groups
struct Groups {
let xcet, juyt, someRandomKey: Juyt
}
// MARK: - Juyt
struct Juyt {
let name: String
let createdDate: Date
}
Thank you #shakif_ for your insightful answer. Here is how I solved this based on that answer -
import ObjectMapper
import RealmSwift
class Person: BaseObject {
#objc dynamic var ID: Int = -1
#objc dynamic var name: String = ""
#objc dynamic var age: Int = -1
var friendsList = List<Friends>()
var groups = List<Group>
override func mapping(map: ObjectMapper.Map) {
ID <- map["id"]
name <- map["name"]
age <- map["age"]
friendsList <- map["friends"]
groups = extractGroups(map)
}
private func extractGroups(_ map: ObjectMapper.Map) -> List<Group> {
let items = List<Group>()
var modifiedJSON = [String: Group]
modifiedJSON <- map["groups"]
for (key,value) in modifiedJSON {
let item = GroupMapper(key: key, value: value)
if let group = item.value {
items.append(group)
}
}
return items
}
}
class Friends: BaseObject {
#objc dynamic var firstName: String = ""
#objc dynamic var lastName: String = ""
#objc dynamic var avatarURL: String = ""
override func mapping(map: ObjectMapper.Map) {
firstName <- map["firstName"]
lastName <- map["name"]
avatarURL <- map["avatar_url"]
}
}
class Group: BaseObject {
#objc dynamic var name: String = ""
#objc dynamic var createdDate: String = ""
override func mapping(map: ObjectMapper.Map) {
name <- map["name"]
createdDate <- map["createdDate"]
}
}
struct GroupMapper {
var key: String = ""
var value: Group?
}

How to use Codable encode with object inside object

Im working on a JSON payload with my object payload. but im having trouble encoding object inside object.
My Payload class was this
class ConversationPayload :BaseObject {
var title : String? = ""
var messageDict: MessagePayload = MessagePayload()
var participants: [Int32] = []
var type: String = ""
enum CodingKeys: String, CodingKey {
case title = "title"
case messageDict = "message"
case participants = "participants"
case type = "type"
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if title != nil {
try container.encode(title, forKey: .title)
}
try container.encode(messageDict, forKey: .messageDict)
try container.encode(participants, forKey: .participants)
try container.encode(type, forKey: .type)
}
}
class MessagePayload: BaseObject {
var body : String = ""
var isVideocallInvite: Bool = false
var attachmentsPayload: MessageAttachmentPayload? = nil
enum CodingKeys: String, CodingKey {
case body = "body"
case isVideocallInvite = "is_videocall_invite"
case attachmentsPayload = "attachment"
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(body, forKey: .body)
try container.encode(isVideocallInvite, forKey: .isVideocallInvite)
if attachmentsPayload != nil {
try container.encode(attachmentsPayload, forKey: .attachmentsPayload)
}
}
}
class MessageAttachmentPayload: BaseObject {
var photo : String = ""
var photoType : String = "jpg"
}
BaseObject was this
class BaseObject:Codable{}
What i want to get in json payload was something like this
{"message": {"body": "body_string", "is_videocall_invite": 1}, "participants" : [user-id], "type" : "converstation_type","title":"title"}
anyone know whats wrong with my payload class? not that familiar yet on codable. thanks in advance.
I'm not sure what constrains you have here, but I would simplify all of this down. Keep the JSON data models as close to the JSON as you can get.
struct ConversationJsonModel: Codable {
var title: String?
var message: MessageJsonModel
var participants: [Int]
var type: String
}
struct MessageJsonModel: Codable {
var body: String
var is_videocall_invite: Int
var attachment: AttachmentJsonModel?
}
struct AttachmentJsonModel: Codable {
var photo: String
var photo_type: String // <-- assuming photo_type is the JSON member name.
}
If you need a view model or some other kind of local data model, then the two parts are separate.
class BaseObject {}
class ConversationPayload: BaseObject {
var title : String? = ""
var messageDict: MessagePayload = MessagePayload()
var participants: [Int32] = []
var type: String = ""
func makeConversationJsonModel() -> ConversationJsonModel {
ConversationJsonModel(title: title,
message: messageDict.makeMessageJsonModel(),
participants: participants.map { Int($0) },
type: type)
}
}
class MessagePayload: BaseObject {
var body : String = ""
var isVideocallInvite: Bool = false
var attachmentsPayload: MessageAttachmentPayload? = nil
func makeMessageJsonModel() -> MessageJsonModel {
MessageJsonModel(body: body,
is_videocall_invite: isVideocallInvite ? 1 : 0,
attachment: attachmentsPayload?.makeAttachmentJsonModel())
}
}
class MessageAttachmentPayload: BaseObject {
var photo : String = ""
var photoType : String = "jpg"
func makeAttachmentJsonModel() -> AttachmentJsonModel {
AttachmentJsonModel(photo: photo, photo_type: photoType)
}
}
Finally, encoding your JSON
let conversationPayload = ConversationPayload()
let json = try? JSONEncoder().encode(conversationPayload.makeConversationJsonModel())
This allows for clean separation between the JSON representation and the payload model. For example, in the JSON, is_videocall_invite is an Int (0 or 1); meanwhile, in the payload model, isVideocallInvite is a Bool.
What is the issue? I just tested your class, it has some minor issues but it does conforming to codable and it encoded without issue.
In playground:
var conversation = ConversationPayload()
var message = MessagePayload()
message.body = "message body"
message.isVideocallInvite = true
var attachment = MessageAttachmentPayload()
attachment.photo = "attachment_file"
message.attachmentsPayload = attachment
conversation.messageDict = message
conversation.title = "Title"
conversation.participants = [1, 2, 3, 4]
conversation.type = "Conversation Type"
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try! encoder.encode(conversation)
print(String(data: data, encoding: .utf8)!)
The output looks like the following:
{
"participants" : [
1,
2,
3,
4
],
"message" : {
"is_videocall_invite" : true,
"attachment" : {
"photo" : "attachment_file",
"photoType" : "jpg"
},
"body" : "message body"
},
"title" : "Title",
"type" : "Conversation Type"
}
I have added encode and CodingKey in MessageAttachmentPayload class to encode the values.
Isn't it what you were expecting?

how to map the data which has array of data

My response is :
[
{
"menu_code" : "NDS",
"items" : [
{
"unit" : "Nos",
"name" : "Chapathi\/Pulkas",
"quantity" : 2
},
{
"unit" : "Cup",
"name" : "Palya\/Curry",
"quantity" : 1
}
],
"is_active" : 1,
"image" : "nds.jpg",
"menu_name" : "Normal Diet South"
},
{
"menu_code" : "NCCD",
"items" : [
{
"menu_code" : "NDS",
"name" : "Monday"
},
{
"menu_code" : "NDN",
"name" : "Tuesday"
}
],
"is_active" : 1,
"image" : "NCCD.jpg",
"menu_name" : "Normal Combo Corporate Diet"
}
]
Today 2 format i have .In this both format only my data will come from response.And i need to show them in collection view.
My api call :
func getAllCatogory(){
TransportManager.sharedInstance.AllCatogory { (dt, err) in
if let _ = err{
}else{
if let data = dt as? String {
let pro = Mapper<AllCatagories>().map(JSONString: data)
print(data) // getting data
print(pro as Any) // getting nil
}
}
}
}
My model :
class AllCatagories: Mappable{
var menu_code = ""
var items: Array<AllCatProducts> = []
var is_active = 0
var image = ""
var menu_name = ""
required init?(map: Map) {
}
init() {
}
func mapping(map: Map) {
menu_name <- map["menu_name"]
is_active <- map["is_active"]
menu_code <- map["menu_code"]
image <- map["image"]
items <- map["items"]
}
}
Below i have created one more model class for the item inside my json.
class AllCatProducts: Mappable{
var name = ""
var quantity = 0
var unit = ""
var menu_code = ""
required init?(map: Map) {
}
init() {
}
func mapping(map: Map) {
name <- map["name"]
quantity <- map["quantity"]
unit <- map["unit"]
menu_code <- map["menu_code"]
}
}
The issues is i am getting nil in my pro.Not sure when i am doing wrong.
Thanks
You can try
struct AllCatagories: Codable {
let menuCode: String
let items: [AllCatProducts]
let isActive: Int
let image, menuName: String
}
struct AllCatProducts: Codable {
let unit: String?
let name: String
let quantity: Int?
let menuCode: String?
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let str = dt as? String else { return }
let res = try decoder.decode([AllCatagories].self, from:str.data(using: .utf8)!)
print(res)
}
catch {
print(error)
}

How to store an array that is within an another array to a global variable that has been passed from JSON in Swift?

I have a JSON which receives an array from an API call
Within that array are 3 other arrays:
userDetails, userStats, communities
An example of this API call is:
["communities": <__NSArrayI 0x6000002540a0>(
{
id = 5;
name = South;
},
{
id = 13;
name = HurraHarry;
},
{
id = 15;
name = EnclliffeT;
}
)
, "userStats": {
totalDraws = 3;
totalLosses = 10;
totalWins = 1;
}, "userDetails": {
id = 31;
"user_email" = "steve#gmail.com";
"user_name" = "Steve Base";
}]
I would like to store the array userStats in a variable that I can pass to another VC.
I have a global variable var userStatsArray = [AnyObject]() in my class
and the following code deals with the JSON:
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json!)
if let arr = json?["communities"] as? [[String:String]] {
self.communitiesArray = arr.flatMap { $0["name"]!}
self.communityIdsArray = arr.flatMap { $0["id"]!}
}
if let dict = json?["userDetails"] as? [String:String] {
self.tempPlayerId = [dict["id"]!]
let characterArray = self.tempPlayerId.flatMap { String.CharacterView($0) }
let newPlayerId = String(characterArray)
self.playerId = newPlayerId
}
if let tempArray = json?["userStats"] as? [String:AnyObject]{
print ("here ", tempArray)
}
The print command successfully prints the userStats array with all its headers (totalWins, totalDraws, totalLosses...) -
How do I store this array into my global variable var userStatsArray = [AnyObject]() so I can pass it to another VC?
Better you create one custom class like this, and declare the array with that custom class type. then you cast your userStats object to your custom class type.
class userStats: NSObject {
var totalDraws: NSNumber?
var totalLosses: NSNumber?
var totalWins: NSNumber?
init(totalDraws: NSNumber?, totalLosses: NSNumber?, totalWins: NSNumber?) {
self.totalDraws = totalDraws
self.totalWins = totalWins
self.totalLosses = totalLosses
}
}
var userStatsArray = [userStats]()
// CHANGE YOUR CODE LIKE THIS
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json!)
if let arr = json?["communities"] as? [[String:String]] {
self.communitiesArray = arr.flatMap { $0["name"]!}
self.communityIdsArray = arr.flatMap { $0["id"]!}
}
if let dict = json?["userDetails"] as? [String:String] {
self.tempPlayerId = [dict["id"]!]
let characterArray = self.tempPlayerId.flatMap { String.CharacterView($0) }
let newPlayerId = String(characterArray)
self.playerId = newPlayerId
}
if let tempArray = json?["userStats"]as? userStats {
userSytatsArray.append(tempArray)
}
Take a look at ObjectMapper! With that powerful framework you can create the mappable models of your data returned by the API and let it perform the whole work for you :)
Declare your model classes like this:
class UserInfo: Mappable {
var communities : [Community]?
var stats: UserStats?
var details: UserDetails?
required init?(map: Map) {
}
func mapping(map: Map) {
communities <- map["communities"]
stats <- map["userStats"]
details <- map["userDetails"]
}
}
class Community: Mappable {
var id: Int!
var name: String!
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
}
}
class UserStats: Mappable {
var totalDraws : Int!
var totalLosses : Int!
var totalWins : Int!
required init?(map: Map) {
}
func mapping(map: Map) {
totalDraws <- map["totalDraws"]
totalLosses <- map["totalLosses"]
totalWins <- map["totalWins"]
}
}
class UserDetails: Mappable {
var id : Int!
var email : String!
var username : String!
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
email <- map["user_email"]
username <- map["user_name"]
}
}
And later just:
let user = UserInfo(JSONString: JSONString)

How to append object in Mappable class(Model). iOS swift

In my app, I'm using Alamofire-ObjectMapper.
I have a [OrderDetailSecond]. now i want to use for loop for this array and when isRxMedicine == 1 i want to add that object in any array so i can display that in my UITableView.
here is my code
this is my model
class OrderDetailSecond: Mappable {
var id : Int?
var isRxMedicine : Int?
var medicineTypeId : String?
var name : String?
var orderId : String?
var price : String?
var quentity : Int?
var strength : String?
required init?(_ map: Map){
}
func mapping(map: Map) {
id <- map["id"]
isRxMedicine <- map["is_rx_medicine"]
medicineTypeId <- map["medicine_type_id"]
name <- map["name"]
orderId <- map["order_id"]
price <- map["price"]
quentity <- map["qty"]
strength <- map["strengh"]
}
}
now here i am trying to add objects in new element
if let Rx_OrderDetail = self.orderdetailInstance, Rx_detail = Rx_OrderDetail.result{
let detailArray = Rx_detail[0].orederDetail
if let orderdata = detailArray
{
for RxDataFilter in orderdata
{
if (RxDataFilter.isRxMedicine == 1)
{
array?.append(RxDataFilter)
}
}
elementConunt = orderdata.count
}
return elementConunt
}
but its not working
Note: orderdata is in form [OrderDetailSecond]

Resources