Parsing strange JSON - swift - ios

I am starting my adventure with Swift and iOS developing. And I am fighting for few hours with parsing this json result:
[
[
{
"id": 289462,
"value": "24.80",
"taken_at": "2017-07-02 19:03:03",
"key": "temperature"
}
],
[
{
"id": 289463,
"value": "52.20",
"taken_at": "2017-07-02 19:03:05",
"key": "humidity"
}
]
]
It hasn't got this "name" before all of results, and I don't know, maybe this is causing errors? And below is my function to get data:
func get_data()
{
let headers = [
"content-type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"postman-token": "fd20c3c4-650e-743c-3066-597de91f3873"
]
let postData = NSMutableData(data: "auth_key=32fd26f62677e7aa56027d9c228e1e9d6d96abc5d10f547dcb66e2a2f6ed13".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://192.168.0.22/last")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
// print(error)
} else {
//let httpResponse = response as? HTTPURLResponse
var keys = [String]()
do {
if let data = data,
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let mes = json[""] as? [[String: Any]] {
for me in mes {
if let name = me["key"] as? String {
keys.append(name)
}
}
}
} catch {
print("Error deserializing JSON: \(error)")
}
print(keys)
}
})
dataTask.resume()
}
I've tried several codes from different sites which I googled and still array is remaining empty :(

You're right the JSON is strange, the root object is [[Any]]. You can get the key values with
if let json = try JSONSerialization.jsonObject(with: data) as? [[Any]] {
for item in json {
if let firstItem = item.first as? [String:Any], let key = firstItem["key"] as? String {
keys.append(key)
}
}
}
However if the JSON was in much more suitable format
[
{
"id": 289462,
"value": "24.80",
"taken_at": "2017-07-02 19:03:03",
"key": "temperature"
},
{
"id": 289463,
"value": "52.20",
"taken_at": "2017-07-02 19:03:05",
"key": "humidity"
}
]
you could reduce the code to
if let json = try JSONSerialization.jsonObject(with: data) as? [[String:Any]] {
keys = json.flatMap { $0["key"] as? String }
}

Related

How to parse this JSON response in Swift

I usually use this code to parse most of JSON responses
Before the code, here the JSON I need to get form it the "workspace"
{
"count": 1,
"next": null,
"previous": null,
"results": [{
"id": 307,
"email": "999#ios.net",
"firstName": "fighter",
"categories": [],
"workspace": 302,
"phone": "25485"
}]
}
here is my code:
func getWorkSpace() {
DispatchQueue.main.async {
let returnAccessToken: String? = UserDefaults.standard.object(forKey: "accessToken") as? String
print("UserDefaults Returned Access Token is: \(returnAccessToken!)")
let access = returnAccessToken!
let headers = [
"content-type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"postman-token": "dded3e97-77a5-5632-93b7-dec77d26ba99",
"Authorization": "JWT \(access)"
]
let request = NSMutableURLRequest(url: NSURL(string: "https://v5/workspaces/")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error!)
} else {
if let dataNew = data, let responseString = String(data: dataNew, encoding: .utf8) {
print("--------")
print(responseString)
print("--------")
DispatchQueue.main.async {
do {
let json = try JSON(data: data!, options: .allowFragments)
let answer = json["results"]
let workspace = Int(answer["workspace"].int!)
// let workspace = Int(answer["workspace"].string!)!
// let workspace = answer["workspace"].int!
print("Workspace is: \(workspace)")
} catch {
print("Error saving workspace!")
}
}
}
}
})
dataTask.resume()
}
}
This code usually works for me, but this time it's not. Please don't suggest me to use Codables because I didn't learn them yet.
SwiftyJSON
do {
let json = try JSON(data: data1!)
let answer = json["results"].array
answer?.forEach {
print($0["workspace"].int!)
}
} catch {
print("Error saving workspace!")
}
JSONSerialization
let json = try! JSONSerialization.jsonObject(with:data, options :[]) as! [String:Any]
let results = json["results"] as! [[String:Any]]
results.forEach {
print($0["workspace"] as! Int)
}
Codable
struct Root : Codable {
let results:[Model]
}
struct Model: Codable {
let id: Int
let email, firstName: String
let workspace: Int
let phone: String
}
let res = try! JSONDecoder().decode(Root.self, from:data)
print(res.results)

send multi part form data in swift

I used this code below to send multipart params
let headers = [
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer \(myToken)",
"cache-control": "no-cache"
]
let parameters = [
[
"name": "firstname",
"value": "alex"
],
[
"name": "lastname",
"value": "black"
],
[
"name": "birthdate_day",
"value": "1"
],
[
"name": "birthdate_month",
"value": "5"
],
[
"name": "birthdate_year",
"value": "1989"
],
[
"name": "gender",
"value": "m"
],
[
"name": "avatar",
"fileName": "\(imageURL)"
]
]
let boundary = "Boundary-\(NSUUID().uuidString)"
var body = ""
let error: NSError? = nil
for param in parameters {
let paramName = param["name"]!
body += "--\(boundary)\r\n"
body += "Content-Disposition:form-data; name=\"\(paramName)\""
if let filename = param["fileName"] {
if let contentType = param["content-type"] {
do {
let fileContent = try String(contentsOfFile: filename, encoding: String.Encoding.utf8)
if (error != nil) {
print(error as Any)
}
body += "; filename=\"\(filename)\"\r\n"
body += "Content-Type: \(contentType)\r\n\r\n"
body += fileContent
} catch {
print(error)
}
}
} else if let paramValue = param["value"] {
body += "\r\n\r\n\(paramValue)"
}
}
let postData = NSMutableData(data: body.data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "myUrl")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error as Any)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse?.statusCode as Any)
}
})
dataTask.resume()
return dataTask
the image url and the rest of the data But I will receive Satus code 500 I know that this error is server side But the android version is using the same api url and that's working well I know that this code can be fix and maybe small changes can fix this code for working
use URL instead of NSURL
var request = URLRequest is mutable, use this instead of NSMutableURLRequest
var data = Data() is mutable, use this instead of NSMutableData
append the file blob data safely using Data(contentsOf:options:) method
content-type is missing in parameters, so if let contentType = param["content-type"] { ... } will fail to proceed, using application/octet-stream default mime type
depending on the server, it might be necessary to provide a filename for the uploads
I fixed all above concerns and moved the URLRequest.httpBody generating code to following extension.
extension URLRequest {
private func formHeader(_ name: String, crlf: String, fileName: String? = nil, mimeType: String? = nil) -> String {
var str = "\(crlf)Content-Disposition: form-data; name=\"\(name)\""
guard fileName != nil || mimeType != nil else { return str + crlf + crlf }
if let name = fileName {
str += "; filename=\"\(name)\""
}
str += crlf
if let type = mimeType {
str += "Content-Type: \(type)\(crlf)"
}
return str + crlf
}
private func getFileUrl(_ file: Any) -> URL? {
if let url = file as? String {
return URL(string: url)
}
return file as? URL
}
private func getFileData(_ url: URL) -> Data? {
do {
return try Data(contentsOf: url, options: .mappedIfSafe)
} catch {
print(error)
return nil
}
}
mutating func setPost(body parameters: [[String: Any]]) {
let boundary = "Boundary+\(arc4random())\(arc4random())"
self.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
data.append("--\(boundary)".data(using: .utf8)!)
let crlf = "\r\n"
for parameter in parameters {
guard let paramName = parameter["name"] as? String else { continue }
if let value = parameter["value"] {
let header = formHeader(paramName, crlf: crlf)
data.append("\(header)\(value)".data(using: .utf8)!)
} else if let file = parameter["file"], let fileUrl = getFileUrl(file), let fileData = getFileData(fileUrl) {
let fileName = parameter["fileName"] as? String
let contentType = parameter["content-type"] as? String
let header = formHeader(paramName, crlf: crlf, fileName: fileName ?? fileUrl.lastPathComponent, mimeType: contentType ?? "application/octet-stream")
data.append(header.data(using: .utf8)!)
data.append(fileData)
} else {
print("\(paramName): empty or invalid value")
continue
}
data.append("\(crlf)--\(boundary)".data(using: .utf8)!)
}
data.append("--\(crlf)".data(using: .utf8)!)
self.httpBody = data
self.httpMethod = "POST"
}
}
Usage
let parameters = [
["name": "firstname", "value": "alex"],
["name": "avatar", "file": URL],
["name": "avatar", "file": "file:///", "fileName": "image.png", "content-type": "image/png"]
]
request.setPost(body: parameters)
Note above in parameters
file key represents either a URL object or file path String.
fileName: image.png is for backend, represents name of the file.
Finally add headers and create URLSession.shared.dataTask as your original code.
Update-2 function instead of an extension
func getParameterData(_ name: String, parameter: [String : Any]) -> Data? {
var str = "\r\nContent-Disposition: form-data; name=\"\(name)\""
if let value = parameter["value"] {
return "\(str)\r\n\r\n\(value)".data(using: .utf8)!
}
guard
let file = parameter["file"],
let url = (file is String ? URL(string: file as! String) : file as? URL)
else {
return nil
}
let data: Data
do {
data = try Data(contentsOf: url, options: .mappedIfSafe)
} catch {
print(error)
return nil
}
let fileName = (parameter["fileName"] as? String) ?? url.lastPathComponent
str += "; filename=\"\(fileName)\"\r\n"
let contentType = (parameter["content-type"] as? String) ?? "application/octet-stream"
str += "Content-Type: \(contentType)\r\n"
return (str + "\r\n").data(using: .utf8)! + data
}
func setPostRequestBody(_ request: inout URLRequest, parameters: [[String: Any]]) {
let boundary = "Boundary+\(arc4random())\(arc4random())"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
data.append("--\(boundary)".data(using: .utf8)!)
for parameter in parameters {
guard
let name = parameter["name"] as? String,
let value = getParameterData(name, parameter: parameter)
else {
continue
}
data.append(value)
data.append("\r\n--\(boundary)".data(using: .utf8)!)
}
data.append("--\r\n".data(using: .utf8)!)
request.httpBody = data
}
Usage-2
var request = URLRequest(url: URL(string: "myUrl")!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
setPostRequestBody(&request, parameters: [
["name": "firstname", "value": "alex"],
["name": "avatar", "file": URL object or path String]
])
let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
guard error != nil else {
print(error!.localizedDescription)
return
}
let statusCocde = (response as? HTTPURLResponse)?.statusCode
print(statusCode ?? 0)
if let data = data {
print(String(data: data, encoding: .utf8) ?? "")
}
}
dataTask.resume()

Text Detection problems with Google Vision

Not sure what the issues is as my code just stopped working overnight, but the text detection on Google Vision is either returning nil or returning words that are non-existent on the subject.
Here's my request function:
func createRequest(with imageBase64: String) {
let jsonRequest = [
"requests": [
"image": [
"content": imageBase64 ],
"features": [
["type": "TEXT_DETECTION"],
["type": "IMAGE_PROPERTIES"]
]
]
]
let jsonData = try? JSONSerialization.data(withJSONObject: jsonRequest)
var request = URLRequest(url: googleURL)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(Bundle.main.bundleIdentifier ?? "", forHTTPHeaderField: "X-Ios-Bundle-Identifier")
request.httpBody = jsonData
DispatchQueue.global().async {
let task: URLSessionDataTask = self.URLsession.dataTask(with: request) { (encodedObject, response, error) in
guard let data = encodedObject, error == nil else {
print(error?.localizedDescription ?? "no data")
return
}
self.analyzeResults(data)
}
task.resume()
}
}
Part of my analyze results function:
func analyzeResults(_ data: Data) {
DispatchQueue.main.async {
guard let response = try? JSONDecoder().decode(Root.self, from: data) else { return }
guard let responseArray = response.responses else { return }
print(response)

Not able to login with api calling and not able to save the access id

This is my first application i am working on.I have one api url for login calling function. And when i enter username, password. It will generate one customer id.And i need to save that is, and i have to use that particular id for all my screen till user logged out.
But when i am doing api calling for login . Its not working. Please help me out.
This is my parameter passing :
{
"username" : "u#gmail.com",
"password" : "u123"
}
My json output after login api call :
{
"status": 1,
"message": "Login success.",
"CustomerDetails": {
"CustomerId": "1",
"CustomerName": "u",
"CustomerEmail": "u#gmail.com",
"CustomerMobile": "901",
"CustomerAddress": "#45, 7th main road."
}
}
In this i need to save the CustomerId and i have to use that CustomerId to all my screens.
My api calling fuction while login button tap :
func getcartdetaildata () {
let headers = [
"cache-control": "no-cache",
"postman-token": "4c933910-0da0-b199-257b-28fb0b5a89ec"
]
let jsonObj:Dictionary<String, Any> = [
"username" : "\(UsernameEmail)",
"password" : "\(Password)"
]
if (!JSONSerialization.isValidJSONObject(jsonObj)) {
print("is not a valid json object")
return
}
if let postData = try? JSONSerialization.data(withJSONObject: jsonObj, options: JSONSerialization.WritingOptions.prettyPrinted) {
let request = NSMutableURLRequest(url: NSURL(string: "http://Login.php")! as URL,
cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
///print(error)
} else {
print("123.......... ")
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? Dictionary<String,AnyObject>
{
print(json)
let status = json["status"] as? Int;
if(status == 1)
{
print("asdasdasx.......... ")
// let access_token = json["CustomerId"]
//print(access_token)
DispatchQueue.main.async(execute: {
//
//
// //Set logged in to true
// UserDefaults.standard.set(true, forKey: "ISLOGGEDIN")
//
// //Set access token
// UserDefaults.standard.setValue(access_token, forKey: "CustomerId")
//
// UserDefaults.standard.synchronize()
//
})
}
}
})
}
})
dataTask.resume()
}
}
Please help me out.
Thanks
func apicalling () {
let Username:NSString = EmailTextField.text! as NSString
let password:NSString = PasswordTextField.text! as NSString
let headers = [
"content-type": "application/json",
"cache-control": "no-cache",
"postman-token": "4c933910-0da0-b199-257b-28fb0b5a89ec"
]
let parameters = [
"username": "\(Username)",
"password": "\(password)"
]
do {
let postData = try JSONSerialization.data(withJSONObject: parameters, options :[])
let request = NSMutableURLRequest(url: NSURL(string: "http://Login.php")! as URL,cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
///print(error)
} else {
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? Dictionary<String,AnyObject>
{
let status = json["status"] as? Int;
if(status == 1)
{
print(json)
}
}
})
}
})
dataTask.resume()
} catch {
// print("JSON serialization failed: \(error)")
}
}
Code for save data in NSUserDefaults.
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(YOUR_VALUE, forKey: "PASSKEY")
userDefaults.synchronize() // don't forgot this line
Retriving data from NSUserDefaults
if let VARIABLE = userDefaults.valueForKey("PASSKEY") {
// do something here when a Data exists
}
else {
// no data exists
}

Swift and JSON parsing only an object not an array

I am working on a weather app that parses JSON data and sets the text of my label to the temp value of the JSON request. I got the value of id from the weather object array, but the temp is not in an array it is just an object. Can someone please tell me where I am wrong. My value is reurning nil because I am not fetching it correctly. Here is my snippet and JSON.
#IBAction func getWeather(sender: AnyObject) {
let requestURL: NSURL = NSURL(string: "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=MYAPPID")!
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) {
print("JSON Downloaded Sucessfully.")
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let today = json["weather"] as? [[String: AnyObject]] {
//this is pulling 4 key value pairs
for weather in today {
//this works
let id = weather["id"]?.stringValue
self.trumpDescription.text=id;
print(id)
//this is where I am confused it changes from an array to just an object
let temp = json["temp"] as? String
self.currentTempView.text=temp;
print(temp)
}
}
}
catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
}`
Here is the JSON:
{
"coord": {
"lon": 138.93,
"lat": 34.97
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"base": "cmc stations",
"main": {
"temp": 292.581,
"pressure": 1019.48,
"humidity": 99,
"temp_min": 292.581,
"temp_max": 292.581,
"sea_level": 1028.92,
"grnd_level": 1019.48
},
"wind": {
"speed": 5.36,
"deg": 237.505
},
"clouds": {
"all": 64
},
"dt": 1464964606,
"sys": {
"message": 0.0037,
"country": "JP",
"sunrise": 1464895855,
"sunset": 1464947666
},
"id": 1851632,
"name": "Shuzenji",
"cod": 200
}
It looks like it should be
if let main = json["main"] as? NSDictionary {
let temp = main["temp"] as! String
print(temp)
}
Instead of this:
let temp = json["temp"] as? String
Try this:
if let main = json["main"] as? [String: AnyObject] {
let temp = main[temp]?.stringValue
print(temp)
//alternatively you can try this as per your convenience of data type
let tempNew = main[temp]?.doubleValue
print(tempNew)
}

Resources