Save json response and parse it into swift object - json

Hey I am programming a swift app and I consume a rest service for my data.
I consume it like this:
static func findAll() {
let URL = baseURL + "api/person"
Alamofire.request(URL).responseJSON {
response in
print(response.result.value ?? "")
}
}
This is the json that is returned:
{
Email = "meineEmail#gmail.com";
Geburtsdatum = "0001-01-01T00:00:00";
Nachname = Gnadlinger;
Password = "<null>";
PersonId = 0;
Telefonnummer = 9832742;
Username = SonnyBlackzz;
Vorname = Johannes;
}
Is there a way to save these json values and parse them into an object?
Best regards!

Just create an object eg:
struct Person {
var username: String
var email: String
init(username: String, email: String) {
self.username = username
self.email = email
}
}
And when you get your data just do this:
Alamofire.request(URL).responseJSON {
response in
let json = response.result.value
guard let json != nil else {
return
}
let newPerson = Person(username: json["username"], email: json["email"])
}

Related

Iterate over JSON and stored pointers in Swift

After receiving a JSON payload from a web request, I need to parse out the data into variables in an NSObject subclass.
My variables are declared in the object:
var name:String?
var email:String?
var aboutMe:String?
Then I start parsing through all the possible data the JSON may return:
if let name = json["Name"] as? String
{
self.name = name
}
if let email = json["Email"] as? String
{
self.email = email
}
if let aboutMe = json["AboutMe"] as? String
{
self.aboutMe = aboutMe
}
This is becoming rather long as we have a lot of data.
I was wanting to shorted it by using a Dictionary containing the JSON key and the variable like this:
let varMap:[String:Any?] = [
"Name": self.name,
"Email": self.email,
"AboutMe": self.aboutMe
]
Then iterating over them like this:
for (key, var variable) in varMap
{
if let string = json[key]
{
variable = string
}
}
The problem here is that the Dictionary copies the value from the variable and not a pointer to it, so setting it to a new value has no effect on the variables of the overall object.
Is there a way to achieve what I am trying? If not, what other pattern would be a better way to do this instead of having tons of if statements?
For JSON parsing, you can simply use Codable types.
Let's assume your JSON looks like,
{
"name": "Alex",
"email": "alex#gmail.com",
"about_Me": "My name is Alex"
}
Models:
class Root: Decodable {
let name: String?
let email: String?
let aboutMe: String?
enum CodingKeys: String, CodingKey {
case name, email
case aboutMe = "about_Me"
}
}
Parse the JSON data like so,
do {
let response = try JSONDecoder().decode(Root.self, from: data)
print(response) //use response here...
} catch {
print(error)
}
You can use updateValue function for that, it finds the property and changes it.
if let oldValue = varMap.updateValue(self.name, forKey: "Name") {
print("The old value of \(oldValue) was replaced with a new one.")
}
So you for iteration is;
for (key, var variable) in varMap
{
varMap.updateValue(string, forKey: key )
//if let string = json[key]
//{
// variable = string
//}
}
After you update the dictionary you can call that part;
if let name = json["Name"] as? String
{
self.name = name
}
if let email = json["Email"] as? String
{
self.email = email
}
if let aboutMe = json["AboutMe"] as? String
{
self.aboutMe = aboutMe
}
I believe that part in a function, if its not, you can refactor it.
https://developer.apple.com/documentation/swift/dictionary/3127179-updatevalue

Parsing Gravatar Profile JSON in Swift

I am properly loading up my own profile information in an iOS Swift application, but the JSON has an object associated with it which is confusing me on how to properly parse it in order to access the data within it. Here is my method.
func attemptToLoadProfile(hash: String) {
let url = "https://www.gravatar.com/\(hash).json"
let fileURL = URL(string: url)
do {
let contents = try String(contentsOf: fileURL!)
let data = contents.data(using: String.Encoding.utf8)
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
print(json!)
} catch {
print("error parsing json")
}
}
This works fine, but when I print it out, the JSON is formatted like this.
{
entry = (
{
displayName = edolecki;
hash = <myhash here>;
id = 1333520;
name = {
familyName = Dolecki;
formatted = "Eric Dolecki";
givenName = Eric;
};
photos = (
{
type = thumbnail;
value = "https://secure.gravatar.com/avatar/<myhash here>";
}
);
preferredUsername = edolecki;
profileUrl = "http://gravatar.com/edolecki";
requestHash = <myhash here>;
thumbnailUrl = "https://secure.gravatar.com/avatar/<myhash here>";
urls = (
);
}
);
}
How do I parse the JSON seeing there is that entry object at the root? I am after displayName, id, etc. I normally parse JSON without a more simplified root. I haven't seen this before.
The value associated with the entry key is just an array with one element. In this case, you can access json["entry"], cast it to a [[String: Any]] and access the first element [0]. Then you can access the things you want, like displayName and id.
A better way to do this is use Codable. Using QuickType, I generated this code:
struct Root: Codable {
let entry: [Entry]
}
struct Entry: Codable {
let id, hash, requestHash: String
let profileURL: URL
let preferredUsername: String
let thumbnailURL: URL
let photos: [Photo]
let displayName: String
enum CodingKeys: String, CodingKey {
case id, hash, requestHash
case profileURL = "profileUrl"
case preferredUsername
case thumbnailURL = "thumbnailUrl"
case photos, displayName
}
}
struct Photo: Codable {
let value: URL
let type: String
}
Then you can do this to parse the json:
let decoder = JSONDecoder()
let root = try decoder.decode(Root.self, from: data)
// e.g.
let displayName = root.entry[0].displayName
If you don't need any of the json KVPs, just remove it from the struct.

Use Alomofire for get data from server in Xcode 9

I'm beginner in iOS programming but I work in android so now I stuck in a problem in iOS.
I know my question is general but I really need your help!
in android for connect to server we do like below:
Call<String> myList = service.Contact_List("");
myList.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
try{
ArrayList<Contact> contactArrayList = new ArrayList<>();
JSONArray jsonArray = new JSONArray(response.body());
for(int i=0 ; i<jsonArray.length() ; i++)
contactArrayList.add(gson.fromJson(jsonArray.getJSONObject(i).toString(), Contact.class));
}catch (Exception e) {
Log.d("Catch","Error")
}finally {
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("Failure","Error")
}
});
and in xcode I do like below :
let url = URL(string: "http://api.example.com/Contact-List")
Alamofire.request(url!, method: HTTPMethod.post, parameters: param, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
print("response.request")
print(response.request as Any) // original URL request
print("response.response")
print(response.response as Any) // URL response
print("response.result.value")
}
and my result is something like this:
[{"Id":1,"Name":"Mary","TelNumber":"09111111"},{"Id":2,"Name":"Sarah","TelNumber":"09222222"},
{"Id":3,"Name":"Ben","TelNumber":"09333333"}]
now my question is that how can I do like this code in Xcode(swift 3 ):
for(int i=0 ; i<jsonArray.length() ; i++)
contactArrayList.add(gson.fromJson(jsonArray.getJSONObject(i).toString(), Contact.class));
in addition, I use ASP.net in server side.
I am really sorry about my long and ambiguous question!
thanks for any suggestions.
First create NSObject swift file :
then add code
class demo {
var ID: String
var Name: String
init(ID: String, Name: String) {
self.ID = ID
self.Name = Name
}
}
Try like this way :
let data = response.result.value
if data != nil {
self.presentWindow.hideToastActivity()
if let response = data as? [[String: AnyObject]] {
for detail_data in response {
let Id = detail_data["Id"] as? String ?? ""
let Name = detail_data["Name"] as? String ?? ""
let demoObj = demo(ID: ID, Name: Name
self.demoObjects.append(demoObj)
}
}
}
Updated Answer
for converting string response to JSON
Sample code will be something like this. Don't forget to handle unwrap stuff
let data1 = "[{\"Id\": 1,\"Name\": \"Mary\",\"TelNumber\": \"09111111\"},{\"Id\": 2,\"Name\": \"Sarah\",\"TelNumber\": \"09222222\"}]" //your JSON From API Response
let data = data1.data(using: .utf8)
do {
let array = try JSONSerialization.jsonObject(with: data!) as! [[String : Any]]
for detail_data in array {
let Id = detail_data["Id"] as? Int ?? 00
let Name = detail_data["Name"] as? String ?? ""
print("Id:",Id)
print("Name:",Name)
print("****")
}
} catch {
print("Exception occured \(error))")
}

Alamofire decoding by index of array

I have problem with decoding of json , I can't use 'self' function on the struct , because I get json from the server by 1 key (which name "my_profile") and many values , which I return by index , and I want to decode it to the struct , pls help me
Alamofire.request(mainUrl, method:.post , parameters: paramstring , encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
if let data = response.data
{
switch response.result
{
case.failure(let error):
print(error)
case.success(let value):
let json=JSON(value)
guard let dataarr = json["my_profile"].array else { return }
// I wan't send it to the structure , and get it from another view controllers
var name = dataarr[0]
var last_name = dataarr[1]
var email = dataarr[2]
}
}
}
This is my Structure
struct UserInfo : Decodable {
var name : String
var last_name : String
var emai : String
}
Json structure:
It would be better to write an initialiser for your struct:
struct UserInfo : Decodable {
var name : String
var last_name : String
var email : String
init(name: String, lastName: String, email: String) {
self.name = name
self.last_name = lastName
self.email = email
}
}
Then you can use something like this (Adapt it to your specific needs):
let json = JSON(value)
guard let dataarr = json["my_profile"].arrayValue else { return }
let stringArray = dataarr.map { $0.stringValue }
var name = stringArray[0]
var last_name = stringArray[1]
var email = stringArray[2]
let userInfo = UserInfo(name: name, lastName: last_name, email: email)
// use `userInfo` object
To pass the object to a new view controller you should define a variable in the NewViewController to store the userInfo object:
let userInfo: UserInfo!
Then from the code above you should call these lines at the end (it uses storyboard):
// ...
let userInfo = UserInfo(name: name, lastName: last_name, email: email)
let controller = storyboard?.instantiateViewController(withIdentifier: "NewViewController") as! NewViewController
controller.userInfo = userInfo
present(controller, animated: true, completion: nil)
Where NewViewController is the new controller when you'll show the userInfo object content. Don't forget to set the new view controller identifier to NewViewController in the storyboard.

Parse nested elements in JSON

I couldn't seem to parse the following json:
["data": {
companies = (
);
"login_status" = success;
"rs_customer" = {
id = "<null>";
name = "<null>";
status = "<null>";
};
user = {
email = "email#email.com";
id = 0;
lastlogin = "06/14/16 12:44 am";
name = "Jayson Tamayo";
password = mypassword;
phone = "112345";
};
}, "status": success]
I retrieve that JSON thru:
HTTPGetJSON("http://myurl.com") {
(data: Dictionary<String, AnyObject>, error: String?) -> Void in
if error != nil {
print(error)
} else {
print(data)
let status = data["status"] as? String
print(status)
}
}
When I print the "status" it works. But when I try to use data["name"] I get nil. I also tried data["data"]["name"] but I also get nil.
Your main object is a dictionary.
In the "data" key, there's several values: "companies" is an array, "rs_customer" is a dictionary, the statuses are Strings and "user" is a dictionary.
So, to get the user, you would just have to cast to the proper types, something like this, if data is the object we see in the question:
if let content = data["data"] as? [String:AnyObject] {
if let user = content["user"] as? [String:AnyObject] {
if let name = user["name"] as? String {
print(name)
}
}
}
You can also chain the unwrapping for simpler code:
if let content = data["data"] as? [String:AnyObject],
user = content["user"] as? [String:AnyObject],
name = user["name"] as? String {
print(name)
}