How to parse data encode received from php in Swift? - php

I receive data from php file with this format:
{"object:value", "object2:value2"...}
{"object:value", "object2:value2"...}
I know how to parse this in Swift2 using next code repeatedly changing separatedBy string:
if let url = NSURL(string: strURL), let data = NSData(contentsOfURL: url) {
let strResult = NSString(data: data, encoding: NSUTF8StringEncoding)
}
tareas = strResult!.componentsSeparatedByString(",")
But I want parse this more easily. I have read others questions and answers but the format to parse was:
[
{"person": {"name":"Dani","age":"24"}},
{"person": {"name":"ray","age":"70"}}
]
And my data is different. How can I do this more easily?
Thanks!

You can read it as a Array like this
First of all you need to convert your data in valid json like this and then access it
var result: NSArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSArray
println("result: \(result)")
Ex.
var str = "[{\"person\": {\"name\":\"Dani\",\"age\":\"24\"}},{\"person\": {\"name\":\"ray\",\"age\":\"70\"}}]"
var data : NSData = str.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
var result: NSArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSArray
println("Response: \(result)")
println("Oth Object: \(result[0])")
Output
Response: (
{
person = {
age = 24;
name = Dani;
};
},
{
person = {
age = 70;
name = ray;
};
}
)
Oth Object: {
person = {
age = 24;
name = Dani;
};
}

I suggest you to use SwiftyJSON (6k+ stars) library that converts response to JSON object. Something like:
if let url = NSURL(string: strURL), let data = NSData(contentsOfURL: url) {
let json = JSON(data: data!)
}
After that you can easily extract any info from JSON:
for item:JSON in json.arrayValue{
let person = item["person"].dictionaryValue
//...
}
Playground printscreen

Related

I have this issue when trying to read my data which is json encoded from the php page to the swift page

I have this issue when trying to read my data which is json encoded from the php page to the swift page.
this is the code I am using
import Foundation
protocol HomeModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, URLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocol!
var data = Data()
let urlPath: String = "http://localhost/service.php" //this will be changed to the path where service.php lives
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded") // this work fine
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
print(jsonResult) // this print empty parentheses
print(String(data: data, encoding: .utf8)) // this prints out the array
//the code below throughs an arror
do{
jsonResult = try JSONSerialization.jsonObject(with:data, options:JSONSerialization.ReadingOptions.allowFragments) as! [NSArray] as NSArray
print(jsonResult)
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let name = jsonElement["Name"] as? String,
let address = jsonElement["Address"] as? String,
let latitude = jsonElement["Latitude"] as? String,
let longitude = jsonElement["Longitude"] as? String
{
location.name = name
location.address = address
location.latitude = latitude
location.longitude = longitude
}
locations.add(location)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: locations)
})
}
}
this is the output which I am receiving:
Data downloaded
(
)
Optional(" \nconnectedinside[{\"name\":\"One\",\"add\":\"One\",\"lat\":\"1\",\"long\":\"1\"},{\"name\":\"Two\",\"add\":\"Two\",\"lat\":\"2\",\"long\":\"2\"},{\"name\":\"One\",\"add\":\"One\",\"lat\":\"1\",\"long\":\"1\"},{\"name\":\"Two\",\"add\":\"Two\",\"lat\":\"2\",\"long\":\"2\"}]")
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around
character 2." UserInfo={NSDebugDescription=Invalid value around
character 2.}
You get this error, because the json response you receive is not an array but a dictionary.
EDIT: as pointed out in a comment, you first need to fix your json response in your php code. There is ":" missing after "connectedinside".
It should look like this:
{\"connectedinside\":[{\"name\":\"One\",\"add\":"One",...},...]}
My suggestion to fix this:
You should have two models:
struct HomeModelResponse: Codable {
let connectedinside: [LocationModel]
}
// your LocationModel should look like this:
struct LocationModel: Codable {
let name: String
let add: String
let lat: String
let long: String
}
And change your JSONDecoding code to:
do {
jsonResult = try? JSONDecoder().decode(HomeModelResponse.self, from: data)
print()
} catch let exception {
print("received exception while decoding: \(exception)"
}
Then you can access your LocationModels by jsonResult.connectedinside
The problem was on my php side and I fixed it.it is working now.

How do I pass an array in a swift json request

How can I pass an array to my Php backend using swift. Do i have to for loop each value and append it to the request body?
Here is my code
let url = URL(string: "url.com/page")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let id = user?["id"] as! String
let party = partyName.text!
let body = "id=\(id)&party_name=\(party)&party_invited=\(usersInvited)"
//********--usersInvited-- is the array i want to pass
request.httpBody = body.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) in
DispatchQueue.main.async(execute: {
if error == nil{
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
guard let parseJSON = json else{
print("Error while parsing")
return
}
print(parseJSON["status"])
} catch{
print("Caught an error: \(error)")
}
} else{
print("Error: \(error)")
}
})
}).resume()
But that code sends the array as one whole string with an output like this: ["57", "60"]
I'm guessing, but it looks like you want to JSON encode your array, but as a URL parameter?
(I've assumed that usersInvited is an array of strings)
You could go via JSONSerialisation?
let data = try! JSONSerialization.data(withJSONObject: usersInvited, options: [])
let string = String(data: d, encoding: .utf8)!
let body = "id=\(id)&party_name=\(party)&party_invited=\(string)"
Or if that's not quite what you want (you've got a space after the comma in your question), you could just do it by hand?
let string = "[" + usersInvited.map { "\"\($0)\"" }.joined(separator: ", ") + "]"
My vote would be to use option 1 and make your server accept what it outputs.
If you mean you want it to look like party_invited=1,2,3,4 then you could use joined to convert the array like this
let string = usersInvited.joined(separator: ",")
let body = "id=\(id)&party_name=\(party)&party_invited=\(string)"
If you mean you want this party_invited=1&party_invited=2&party_invited=3 then you can use map and joined
let string = usersInvited.map { "party_invited=\($0)" }.joined(separator: "&")
let body = "id=\(id)&party_name=\(party)&\(string)"

Use PHP Response to store/use data

I declared a function to send information from some textfields (POST), then I get a response with the information given. I also used components(separatedBy: String) to get an array with the information from every field. What am trying to do now is to use this information (one from the array) to store/use it so I can show the user, in a new view, the information saved.
My Swift looks like the following
#IBAction func enviarInfo(_ sender: Any) {
let request = NSMutableURLRequest(url: NSURL(string: "http://www.mydomain/index.php")! as URL)
request.httpMethod = "POST"
//The String with the vars that will be sent to the $_POST["var"]
let postString = "nombre=\(nombreText.text!)&aPaterno=\(apaternoText.text!)&aMaterno=\(amaternoText.text!)&genero=\(genero.text! &email=\(emailText.text!)&telefono=\(telefonoText.text!)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(String(describing: error))")
return
}
print("response = \(String(describing: response))")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(String(describing: responseString))")
//Use a split method to get relevant information only
let string: String = responseString! as String
var str = string.components(separatedBy: "##")
let resultadoUno = str[1]
var str2 = resultadoUno.components(separatedBy: ">>")
let resultadoDos = str2[0]
var str3 = resultadoDos.components(separatedBy: ";")
}
task.resume()
}
If I print, for example, str3[5] I get the phone number, or a name with str3[0], but what I don't know is, how to save the data and show it to the user via labels (label.text = the value from the array).
You can easily save Response string to UserDefaults, and restore and use them later.
First, define a class level constant as UserDefaults key:
let key = "responseString"
Second, save the string:
UserDefaults.standard.set(responseString, forKey: key)
UserDefaults.standard.synchronize()
Restore and use it when you need it:
guard let repsonseString = UserDefaults.standard.object(forKey: key) as? String else {
return
}
var strArray = repsonseString.components(separatedBy: "##")
if strArray.count > 0 {
let str2 = strArray[0].components(separatedBy: ">>")
// do something with str2
}
if strArray.count > 1 {
let str3 = strArray[1].components(separatedBy: ";")
if str3.count > 5 {
self.phoneLabel.text = str3[5]
}
}
The better practice is the PHP returns the dictionary instead of array, like:
{
phoneNumber:123456789,
userName:"Joy"
}
You get the response on iOS and convert JSON dictionary to Swift dictionary, and parse it into a Model(Like a User class). Then it will be very convenient to access data like: self.phoneNumberLabel.text = user.phoneNumber

Parse JSON Data to UIPickerView in Swift

I have a UIPickerview which represents countries and i am trying to get its data from MYSQL database but i couldnt handle the coming data from PHP file. I couldnt find any Swift solution so thats why i am here.
//its the default values of pickerview
var pickOption = ["one", "two", "three", "seven", "fifteen"]
func getCountries() {
let url:NSURL = NSURL(string: "http:/domain.com/getCountriesLong.php")!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
let task = session.downloadTaskWithRequest(request) {
(
let location, let response, let error) in
guard let _:NSURL = location, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let urlContents = try! NSString(contentsOfURL: location!, encoding: NSUTF8StringEncoding)
guard let _:NSString = urlContents else {
print("error")
return
}
//all result is here
//print(urlContents)
//string to NSData conversion
let data = urlContents.dataUsingEncoding(NSUTF8StringEncoding)
do {
//parse NSData to JSON
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
//pickOption = json["countryName"]
//pickOption = json
} catch {
print("error serializing JSON: \(error)")
}
}
task.resume()
}
Here is the PHP
$menuData = $db->get_results("SELECT countryName FROM countries ORDER BY countryName ASC");
echo json_encode($menuData);
How can i use coming data as value of my UIPickerView ?
I found the solution. instead of using pickOption = json["countryName"] i have declared new array. Here it is;
var arr = [String]()
for name in json as! [AnyObject] {
if let country = name["countryName"] as? String {
arr.append(country)
}
}
self.pickOption = arr

Parsing JSON without Object name

Here's the usual JSON I see:
{"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]}
But I am trying to parse this format of JSON, without the object ("employees" from the example above):
[{"id":"1","company":"1","facility":"2","starttime":"1454936400","complete_time":"1454979600","scheduled_hours":"12"},{"id":"3","company":"1","facility":"2","starttime":"1455021660","complete_time":"1455061660","scheduled_hours":"12"}]
Here's the code that I'm trying to use:
let requestURL: NSURL = NSURL(string: url)!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let stations = json[1] as? [[String: AnyObject]] {
print(json)
for station in stations {
if let name = station["company"] as? String {
print(name)
}
}
}
}catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
But I am not able to output any of the values from JSON data. How do I do it? I am very new in Swift and XCode.
Or if I can format my data to look like the first JSON, would it be alright? The data is being returned as an array from an SQL query.
UPDATE: When I print(json[1]) it only prints the second set. I think I'm getting closer.
NSJSONSerialization.JSONObjectWithData can be tricky because it can return either an Array aka [AnyObject] or a Dictionary aka [String: AnyObject].
Then you have to test what the result is :
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let json = jsonData as? [[String: AnyObject]] {
// json starts with an array
for value in json {
// loop through array
}
} else if let json = jsonData as? [String: AnyObject] {
// json starts with a key
for (key, value) in json {
// loop through dictionary key/values
}
} else {
// This json is broken
}
1-check that statusCode condition is true(200 or "200"?)
2-print data before try catch
if (statusCode == 200) {
print(data)
do{
......
}
3- print json object
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
print(json)
and
4-check json[1] same as [[String: AnyObject]]

Categories