I want to know if there is a possibility of make a serialization and de-serialization of an object in swift 3.
I have an object like this:
class Credentials{
var username:String;
var password:String;
init(){
username = "";
password = "";
}
}
I want to transform this class into a json (and vice versa ) to send it through HTTP post.
I don't want to use Third party libraries.
Thanks for the answer.
First of all it's not necessary to use a class, a struct is sufficient.
Simple solution with an failable initializer expecting a JSON string and a variable jsonRepresentation
struct Credentials {
var username = ""
var password = ""
init(username: String, password:String) {
self.username = username
self.password = password
}
init?(json : String) {
guard let data = json.data(using: .utf8),
let jsonDict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:String],
let username = jsonDict?["username"],
let password = jsonDict?["password"] else { return nil }
self.username = username
self.password = password
}
var jsonRepresentation : String {
let jsonDict = ["username" : username, "password" : password]
if let data = try? JSONSerialization.data(withJSONObject: jsonDict, options: []),
let jsonString = String(data:data, encoding:.utf8) {
return jsonString
} else { return "" }
}
}
Related
I got a response from web service and try to work on it to put it in a model, but i can't work with it .
this is the response.string
"{\"USER_NO\":1,\"USER_NAME\":\"المسار البديل لتكنولوجيا المعلومات\",\"TASK_CATEGORY_NO\":1,\"USER_ID_NUMBER\":\"1031523473\",\"Mobile_No\":\"0567123432\"}"
I used extension :
extension String{
func tooDictionary() -> NSDictionary {
let blankDict : NSDictionary = [:]
if let data = self.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
} catch {
print(error.localizedDescription)
}
}
return blankDict
}
}
to convert it to dictionary then put it in object but i failed to do that
i'm sorry but i'm new developer in swift4 ,any help please
and thank
Use Decodable:
struct User: Decodable {
private enum CodingKeys : String, CodingKey {
case userNumber = "USER_NO", taskCategoryNumber = "TASK_CATEGORY_NO"
case userName = "USER_NAME", userID = "USER_ID_NUMBER", mobileNumber = "Mobile_No"
}
let userNumber, taskCategoryNumber: Int
let userName, userID, mobileNumber : String
}
let jsonString = """
{"USER_NO":1,"USER_NAME":"المسار البديل لتكنولوجيا المعلومات","TASK_CATEGORY_NO":1,"USER_ID_NUMBER":"1031523473","Mobile_No":"0567123432"}
"""
let data = Data(jsonString.utf8)
do {
let result = try JSONDecoder().decode(User.self, from: data)
print(result)
} catch { print(error) }
Note: Don't use NSArray / NSDictionary in Swift
I need to send json to server in following order
data:{"firstname":"Alpha","lastname":"Beta"}
In this the data key is outside of json like [data:json] but when I am serialization it making the request as
{
"data" : {
"firstname" : "alpha",
"lastname" : "beta"
}
}
These are my models :
struct UserDetail :Codable {
let data :CreateProfileModel
}
struct CreateProfileModel :Codable {
let firstname :String
let lastname :String
}
Data I am adding in these models
let profileInfo = CreateProfileModel(firstname: "alpha" , lastname: "beta")
let userDetails = UserDetail(data: profileInfo)
This is the json encoding that I am doing using swift :
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
do{
let userData = try jsonEncoder.encode(userDetails)
print(String(data: userData, encoding: .utf8)!)
networkListener.requestPost(endpoint: endpoint, data: userData , headerValue: nil)
}catch{
print(error)
}
In requestPost method
func requestPost(endpoint : String , data :Data,headerValue : String?){....
request.httpbody = data
}
I am adding that data the request.httpbody.
How can i add data key with profileInfo ?
Try this Code:
var columnValus:[String:Any] = [:]
columnValus["firstname"] = userDetails.data.firstname
columnValus["lastname"] = userDetails.data.lastname
let userData = [
"data": columnValus
] as [String : Any]
do {
let postData = try JSONSerialization.data(withJSONObject: userData, options: [])
networkListener.requestPost(endpoint: endpoint, data: postData , headerValue: nil)
}catch let error as NSError {
print(error)
}
If the API requires (effectively) HTML form data, you'll need to construct the body yourself and extract bits of JSON.
Try:
let userData = try jsonEncoder.encode(userDetails.data)
let postBodyString = "data:\(userData)"
let postBodyData = postBodyString.data(using: String.Encoding.utf8)
networkListener.requestPost(endpoint: endpoint, data: postBodyData, headerValue: nil)
I have a very simple model struct Student which only has two properties firstName and lastName:
struct Student {
let firstName: String
let lastName: String
init(_ firstName: String, _ lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
// Convert to json data
func toData() -> Data? {
var json = [String: Any]()
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if let key = child.label?.trimmingCharacters(in: .whitespacesAndNewlines) {
json[key] = child.value
}
}
do {
return try JSONSerialization.data(withJSONObject: json, options: [])
} catch {
print("\(error.localizedDescription)")
}
return nil
}
}
As you see above, I created an toData() function which I use to convert model object to JSON data for my HTTP request body.
I create Student instance by:
let student = Student("John", "Smith")
I got Json Data by:
let jsonData = student.toData()
later I set to my URLRequest body by:
request.httpBody = jsonData!
However, backend team always see :
{\"firstName\":\"John\", \"lastName\":\"Smith\"}
But backend expect:
{"firstName":"John", "lastName":"Smith"}
I am sure it is not backend problem. Looks like something needs to improve in my toData() function. But I don't know what to do. Could someone help me?
Try this :
if let jsonString:String = String(data: jsonData!, encoding: String.Encoding.utf8) {
request.httpBody = jsonString.data(using: String.Encoding.utf8)
}
You can get rid of the extra backslashes by converting your struct to a dictionary manually.
I have tested below method using a dummy rest server (rest-server-dummy from npm) and there are no extra backslashes around the "" characters.
struct Student {
let firstName: String
let lastName: String
init(_ firstName: String, _ lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
// Convert to json data
func toData() -> Data? {
var json = [String: Any]()
json["firstName"] = firstName
json["lastname"] = lastName
do {
return try JSONSerialization.data(withJSONObject: json, options: [])
} catch {
print("\(error.localizedDescription)")
}
return nil
}
}
I used this method to send the data to the dummy server running on localhost:
var request = URLRequest(url:URL(string: "http://localhost:8080/username")!)
request.httpMethod = "POST"
request.httpBody = student.toData()
URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
data
response
error
}).resume()
The contents of the output from the server log:
{
"lastname": "Smith",
"firstName": "John"
}
Optional({"session":{"_id":"574fe96fa28f9aaadb000034","application_id":41262,"created_at":"2016-06-02T08:08:15Z","device_id":0,"nonce":21576,"token":"5b04f409c06ecf24ad2d9479a1ef7ef78916f864","ts":1464854895,"updated_at":"2016-06-02T08:08:15Z","user_id":0,"id":7274}})
I need to parse and save token from the above dictionary (in Swift)
My request goes like this :
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let dict = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(dict)")
}
task.resume()
Need to parse dict
JSON parsing/mapping can be a pain and time consuming.
I just happen to have made a tool for it :
Jenerator
Download from here and move to /usr/local/bin/
It is a little command line tool written in Swift to generate a Swift model based on a JSON. If I passed it your JSON it gave me back this :
import Foundation
struct SOSession {
var created_at : String
var _id : String
var id : Int
var device_id : Int
var token : String
var updated_at : String
var nonce : Int
var user_id : Int
var ts : Int
var application_id : Int
init(data:[String:AnyObject]) {
self.created_at = (data["created_at"] as? String) ?? ""
self._id = (data["_id"] as? String) ?? ""
self.id = (data["id"] as? Int) ?? 0
self.device_id = (data["device_id"] as? Int) ?? 0
self.token = (data["token"] as? String) ?? ""
self.updated_at = (data["updated_at"] as? String) ?? ""
self.nonce = (data["nonce"] as? Int) ?? 0
self.user_id = (data["user_id"] as? Int) ?? 0
self.ts = (data["ts"] as? Int) ?? 0
self.application_id = (data["application_id"] as? Int) ?? 0
}
static func fromSource(urlString : String) -> SOSession? {
guard let url = NSURL(string: urlString), data = NSData(contentsOfURL: url) else {
return nil
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
if let outerDict = json as? [String:AnyObject], let dict = outerDict["session"] as? [String:AnyObject] {
return SOSession(data: dict)
}
} catch {}
return nil
}
}
Getting the Token then becomes as simple as this :
let myToken = SOSession.fromSource("someUrl")?.token
To use Jenerator I saved your JSON in a file on my desktop and ran in terminal :
jenerator "$HOME/Desktop/so-1.json" StackOverflowQuestion1 SO
jenerator "path-to-file-with-json" save-file-name class-prefix
You can now copy the generator code to your project.
In Swift 4:
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let data = responseJSON as? [String: Any] {
if let success = data["success"] as? Int {
if success == 1 {
self.dataArray = data["results"] as! Array
label.text = self.dataArray[row]["id"] as? String
// parse in similar fashion
}
}
}
}
I create a swift class as shown below:
class Message {
var type:String
var content:[UInt8] = [UInt8]()
init(type:String, content:[UInt8]) {
self.type = type
self.content = content
}
func jsonAsString()->String {
var dict = [String: AnyObject]()
let mirror = Mirror(reflecting: self)
for (_, attr) in mirror.children.enumerate() {
if let property_name = attr.label as String! {
print("property_name: \(property_name) and value:\(attr.value)")
dict[property_name] = attr.value as? AnyObject
}
}
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions.PrettyPrinted)
return (String(data: jsonData, encoding: NSUTF8StringEncoding)?.stringByReplacingOccurrencesOfString(" ", withString: ""))!
} catch {
NSLog("ERROR when parse JSON")
}
return ""
}
}
I want to call the function 'jsonAsString' to get a json string, but the property 'content' which is an uint8 array not convert correctly.
As I found a lot, some one suggest to replace
var dict = String: AnyObject with
var dict = String: Any
But this type of dictionary is not supported by the method
NSJSONSerialization.dataWithJSONObject(obj: AnyObject, options opt: NSJSONWritingOptions) throws -> NSData