I have a struct as follows
struct UserInfo
{
var userId : Int
var firstName : String
var lastName : String
}
How do I serialize an instance of UserInfo to type Parameters?
var user = UserInfo(userId: 1, firstName: "John", lastName: "Skew")
// Convert user to Parameters for Alamofire
Alamofire.request("https://httpbin.org/post", parameters: parameters)
Just implement a dictionaryRepresentation computed variable or function:
struct UserInfo {
var userId : Int
var firstName : String
var lastName : String
var dictionaryRepresentation: [String: Any] {
return [
"userId" : userId,
"firstName" : firstName,
"lastName" : lastName
]
}
}
Usage:
var user = UserInfo(userId: 1, firstName: "John", lastName: "Skew")
let userDict = user.dictionaryRepresentation
You could use CodableFirebase library. Although it's main purpose is to use it with Firebase Realtime Database and Firestore, it actually does what you need - converts the value into dictionary [String: Any].
Your model would look the following:
struct UserInfo: Codable {
var userId : Int
var firstName : String
var lastName : String
}
And then you would convert it to dictionary in the following way:
import CodableFirebase
let model: UserInfo // here you will create an instance of UserInfo
let dict: [String: Any] = try! FirestoreEncoder().encode(model)
You cannot directly pass struct as parameter. You need to convert your struct into [String:Any]. I have added a new variable description that converts your content to dictionary
struct UserInfo
{
var userId : Int
var firstname : String
var lastname : String
var description:[String:Any] {
get {
return ["userId":userId, "firstname": self.firstname, "lastname": lastname] as [String : Any]
}
}
}
And the usage is
var user = UserInfo(userId: 1, firstname: "John", lastname: "Skew")
// Convert user to Parameters for Alamofire
Alamofire.request("https://httpbin.org/post", parameters: user.description)
If you're going to make parameters to be sent as a POST request then it should take a dictionary format as follows:
let userDict = ["userId" : user.userId, "firstname" : user.firstname, "lastname" : user.lastname]
This should work as "parameters" for your networking
In Swift 4 you can use Decodable/Codable Struct
Related
Im using Firestore and when I request data, it comes in an array
print("Document data: \(dataDescription)")
which prints out
Document data: ["lastname": Test, "firstname": Test]
I created a class
class User {
var firstName: String
var lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
How can I assign the part of the array for "lastname" to the User class and assign in to lastName
A better way to do these parsings of Json to Model and vice versa is by using any parsing library e.g. ObjectMapper, SwiftyJson or swift's Codable protocol. You can do both way parsing with such an ease with them and even for complex data model you don't have to do a lot of work.
So better not to reinvent the wheel.
Here are some examples for your specific usecase.
let userData = ["lastname": "Last", "firstname": "First"]
Using ObjectMapper: (Install pod and add the import to get it work)
struct User: Mappable {
var firstname: String?
var lastname: String?
init?(map: Map) {}
mutating func mapping(map: Map) {
firstname <- map["firstname"]
lastname <- map["lastname"]
}
}
if let newuser = Mapper<User>().map(JSON: userData) {
print(newuser)
}
Using Codeable protocol:
struct User: Codable {
var firstname: String
var lastname: String
}
do {
let data = try JSONSerialization.data(withJSONObject: userData, options: .prettyPrinted)
let decoder = JSONDecoder()
let user = try decoder.decode(User.self, from: data)
} catch {
print(error.localizedDescription)
}
This
["lastname": Test, "firstname": Test]
is a dictionary not an array , you need
guard let res = snap.value as? [String:String] ,let fname = res["firstName"] ,
let lname = res["lastName"] else { return }
let user = User(firstName:fname,lastName:lname)
Tip:think if you really need a struct not class
I want to store the fetched JSON data to my model class array propertyArray. Some how I got the JSON data using Alamofire library and now I want to parse that data to the properties of PropertyList model class. I am not able to parse JSON data to propertyArray. I referred many other solutions to this question on stack overflow but did not get any appropriate solution.
Declared Model Class Array
var propertyArray: [PropertyList]? = []
Alamofire Function
func dataPass() {
print("Landlord id is \(land.id)")
let para: Parameters = ["id": land.id]
Alamofire.request(URL_Landlord_Property_List, method: .post, parameters: para).responseJSON { response in
if let dictionary = response.result.value as? [String : AnyObject]{
var prop = PropertyList()
let data = dictionary["data"] as! [Any]
print(data)
}
}
}
PropertyList
import Foundation
struct PropertyList{
var property_id: String?
var user_id: String?
var property_code: String?
var property_added_date: String?
var property_updated_date: String?
var property_termination_date: String?
var property_ASYS_no: String?
var propertyCode: String?
var property_address_1:String?
var property_address_2: String?
var property_address_3: String?
var property_city: String?
var property_cluster:String?
var property_area:String?
var property_postcode: String?
var property_landlord_ref_code: String?
var property_landlord_id: String?
}
JSON Data
{
"success": true,
"data": [
{
"property_id": "1",
"user_id": "1",
"property_code": "0001",
"property_added_date": "2017-12-13",
"property_updated_date": "2017-12-13 00:00:00",
"property_termination_date": null,
"property_ASYS_no": "ASYS 001",
"propertyCode": "0001-PUNE1",
"property_address_1": "PUNE1",
"property_address_2": "PUNE2",
"property_address_3": "PUNE3",
"property_city": "PUNE",
"property_cluster": "1",
"property_area": "1",
"property_postcode": "424031",
"property_landlord_ref_code": null,
"property_landlord_id": "1"
},
{
"property_id": "2",
"user_id": "1",
"property_code": "0002",
"property_added_date": "2017-12-14",
"property_updated_date": "2017-12-18 00:00:00",
"property_termination_date": null,
"property_ASYS_no": "asys 0200",
"propertyCode": "0002-hadpasar1",
"property_address_1": "hadpasar1",
"property_address_2": "hadpasar2",
"property_address_3": "hadpasar3",
"property_city": "pune",
"property_cluster": "9",
"property_area": "2",
"property_postcode": "012121",
"property_landlord_ref_code": null,
"property_landlord_id": "1"
}
]
}
Looks like your JSON is an array that contains dictionaries. (Key-Value data structure)
This should do the trick.
let data = dictionary["data"] as! [[String: Any]]
Then parse it inside your constructor:
struct PropertyList{
init(dict: [String: Any){
//parse here...
self.property_id = dict["property_id"] as! String
}
}
To add to array:
for dict in data{
let propertyList = PropertyList(dict: dict)
propertyArray.append(propertyList)
}
I have made an API call to log my users in an app. i am using Alamofire and SwiftyJSON. API call works well and I get a JSON file like this one :
{
"code": 200,
"message": "OK",
"data": {
"user_id": 1,
"user_email": "test",
"user_username": "kk1",
}
}
In order to save the user info in UserDefault, I want to create my User object with this JSON response. Here is the model
class LFUser: NSObject {
var user_id: Int?
var user_email: String?
var user_username: String?
init(dict: [String: AnyObject]){
super.init()
user_id = dict["user_id"] as? Int
user_email = dict["user_email"] as? String
user_username = dict["user_username"] as? String
}
}
Here is the part of the login function when the API call and the objectis created :
func login(userEmail: String, userPassword: String, finished: #escaping(_ status:String,_ data: LFUser?)-> ()) {
if let value = response.result.value {
let dict = JSON(value)
let code = dict["code"].intValue
let message = dict["message"].stringValue
if let data = dict["data"].dictionary {
print(data)
let user = LFUser(dict: data as [String : AnyObject])
print(user.user_email)
finished("Success", user)
}
}
The print(data) works well but there is a problem when creating the object and the print(user.user_email) display nil.
Please check this :
if let data = dict["data"].dictionary {
let user = LFUser(dict: data)
print(user.user_email)
finished("Success", user)
}
class LFUser: NSObject {
var user_id: Int?
var user_email: String?
var user_username: String?
init(dict: [String : SwiftyJSON.JSON]){
super.init()
user_id = dict["user_id"]?.intValue
user_email = dict["user_email"]?.stringValue
user_username = dict["user_username"]?.stringValue
}
}
I would go for Swift 4’s Codable instead:
struct User: Codable {
let user_id: Int
let user_email: String
let user_username: String
}
struct Response: Codable {
let code: Int
let message: String
let data: User
}
Then you can decode the incoming data like that:
let response = try JSONDecoder().decode(Response.self, from: jsonData)
Then, in order to save the value to user defaults, you can use JSONEncoder or PropertyListEncoder to encode the value to Data.
I'm receiving following response from server.
[
{
"resourceEmail" : "",
"kind" : "admin#directory#resources#calendars#CalendarResource",
"resourceId" : "",
"resourceName" : "Inubation-Newton-4p",
"resourceType" : "Confroom",
"etags" : "\"eqO3c9wtJJ4wVWz2xe0E9HiU_D0\/rfmk2kZmhGi4HcHadds\""
},
{
"resourceEmail" : "...",
"kind" : "admin#directory#resources#calendars#CalendarResource",
"resourceId" : "...",
"resourceName" : "MVD11-R2-Napolitana",
"resourceType" : "1 Tel Room",
"etags" : "\"eqO3c9wtJJ4wVWz2xe0E9HiU_D0\/zcPwONBLID-O_3gvi0ly\""
},
]
How can I transform above json array to array of custom object. I'm using SwiftyJSON for creating custom object. Below is my custom object class.
class CalendarResource: NSObject {
var resourceID: String
var resourceEmail: String
var resourceName: String
var etags: String
init(json: JSON) {
self.resourceID = json[Constants.Model.CalendarResource.resourceID].stringValue
self.resourceEmail = json[Constants.Model.CalendarResource.resourceEmail].stringValue
self.resourceName = json[Constants.Model.CalendarResource.resourceName].stringValue
self.etags = json[Constants.Model.CalendarResource.etags].stringValue
}
}
Thanks
struct CalendarResource {
var resourceID: String
var resourceEmail: String
var resourceName: String
var etags: String
init(json: JSON) {
self.resourceID = json["resourceID"].stringValue
self.resourceEmail = json["resourceEmail"].stringValue
self.resourceName = json["resourceName"].stringValue
self.etags = json["etags"].stringValue
}
}
And when you are getting response for example like so:
//create array somewhere outside of the method, var calendarResourceArray: [CalendarResource]
let jsonArray = response
self.calendarResourceArray = jsonArray!.map{CalendarResource(json: $0)}
I know in SQL to associate 2 different objects with each other one would use a primary key in 1 table and a foreign key in another table. Since FirebaseDatabase uses JSON/NoSQL that's not possible. If I had 2 objects being UserPostEntity and PostEntity, once a user made a post/comment how would I associate a UserPostEntity with a PostEntity and how would the PostEntity be automatically updated with that post/comment the user made?
UserEntity Object:
import Foundation
class UserEntity{
var userID: String
var postedComment: String
var postDate: String
var postID: PostEntity
init(userID: String, postedComment: String, postDate: String, postID: PostEntity){
self.userID = userID
self.postedComment = postedComment
self.postDate = postDate
self.postID = postID
}
}
PostEntity Object:
import Foundation
class PostEntity{
var userID: String
var postID: String
var postedComment: String
var postDate: String
init(userID: String, postID: String, postedComment: String, postDate: String){
self.userID = userID
self.postID = postID
self.postedComment = postedComment
self.postDate = postDate
}
}
It would be better if you could structure your data in Firebase. Here is the links that provide nice intuition about structuring data in Firebase:
https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html
https://www.firebase.com/docs/web/guide/structuring-data.html
You can define your user table and posts as follow:
user{
"u1" {
userName : "abc",
posts {
p1 : true,
p2 : true
}
},
"u2" {
userName : "def",
posts {
p3 : true,
p4 : true
}
}
}
post{
"p1"{
userId : "u1",
postComment : "hello ios",
postDate : "1467570919"
},
"p2"{
userId : "u1",
postComment : "ios",
postDate : "1467570920"
},
"p3"{
userId : "u2",
postComment : "hello ios",
postDate : "1467570921"
},
"p4"{
userId : "u2",
postComment : "hello ios",
postDate : "1467570922"
}
}
Also you can creates your entities as follow:
class UserEntity{
var userID: String
var userName : String
var posts: Dictionary<String, Bool>?
var ref : FIRDatabaseReference?
init(userID: String, userName: String, posts: Dictionary<String, Bool>?){
self.userID = userID
self.userName = userName
self.posts = posts
self.ref = nil
}
}
class PostEntity{
var pId: String
var uId: String
var postedComment: String
var postDate: NSTimeInterval
var ref : FIRDatabaseReference?
init(pId: String, uId: String, postedComment: String, postDate: NSTimeInterval){
self.pId= pId
self.uId = uId
self.postedComment = postedComment
self.postDate = postDate
self.ref = nil
}
}
Also you would want to structure your UserEntity and PostEntity entity as answered in this post.
You have to update the posts attribute of user table as p5 :true, when a new post p5 is added by user u1.