Swift How to update (modify, Delete, Add) entries of JSON - ios

Hello i need some help here, I'm making an IOS app that gets data from a JSON API and then showing the results on a Table , when i tap on a result from the table it goes to a second view controller where i'm showing the details. What I want to do is to update the info I'm showing on the details, delete entries from the JSON by deleting them from the table itself, and add a new entry to be saved on the JSON.
This is the JSON structure:
{
_id: "57eec6c9dfc2fb03005c0dd0",
ssid: "nonummy",
password: "accumsan",
lat: 29.39293,
lon: 115.71771,
summary: "curae nulla dapibus dolor vel est donec odio justo sollicitudin ut",
__v: 0,
likes: 1,
unlikes: 0,
bssid: "EF:CD:AB:56:34:12"
},
I want to be able to update the SSID, Password and Summary.
this is the code I'm using to get the Result from the JSON and is working good
Code:
let url = URL(string:"https://fierce-peak-97303.herokuapp.com/api/wifi")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
}else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
//print(jsonResult))
for item in(jsonResult as? NSArray)! {
let ssid = (item as? NSDictionary)?["ssid"] as? NSString
//print(ssid)
}
self.tableData = jsonResult as! NSArray
DispatchQueue.main.sync(execute: {
self.table.reloadData()
})
}catch {
print("No Json Result Was Found")
}
}
}
}
task.resume()
For example if I click on one line of the table I want to be able to update password.

I managed to do it like this : all formatted for swift 3
//declare parameter as a dictionary which contains string as key and value combination.
let parameters = ["ssid": newSSID.text!,"password": newPass.text!,"lat": newLat.text!,"lon": newLon.text!,"summary": newSum.text!] as Dictionary<String, String>
//create the url with NSURL
let url = URL(string: "https://fierce-peak-97303.herokuapp.com/api/wifi")
//create the session object
let session = URLSession.shared
//now create the NSMutableRequest object using the url object
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
var err : NSError?
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
}catch{
print("error")
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
print("Response: \(response)")
let strData = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Body: \(strData)")
var err: NSError?
do {
var json = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as? NSDictionary
}catch{
print("JSON error")
}
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
print(err!.localizedDescription)
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as? NSDictionary
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
let success = parseJSON["success"] as? Int
print("Success: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Error could not parse JSON: \(jsonStr)")
}
}catch{
print("JSON error")
}
}

You can get the contents of the json file as whatever data structure you want, then overwrite the values that you want to change and finally overwrite the original file when you want to save your changes:
So you're already getting the JSON as an array:
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
let array = (jsonResult as? NSArray)!
So now you can just change the values in array, when you're done changing everything you want then you can overwrite the json file: (swift 3.0)
var jsonData: NSData!
// serialize json dataa
do
{
jsonData = try JSONSerialization.dataWithJSONObject(array, options: NSJSONWritingOptions())
let jsonString = String(data: jsonData as Data, encoding: String.Encoding.utf8)
print(jsonString)
}
catch let error as NSError
{
print("Array to JSON conversion failed: \(error.localizedDescription)")
}
// overwrite the contents of the original file.
do
{
let file = try FileHandle(forWritingToURL: url!)
file.writeData(jsonData)
print("JSON data was written to the file successfully!")
}
catch let error as NSError
{
print("Couldn't write to file: \(error.localizedDescription)")
}
I'm not sure exactly how writing to a server works, but since it's a URL i think it should act the same way.
Update:
So your original array is:
let array = (jsonResult as? NSArray)!
You can cast it to an array of dictionaries like so
var dictionaries : [[String: NSObject]] = array as? [[String: NSObject]]
and you get ssid by doing:
int i = 0;
for (dictionary in dictionaries)
{
let ssid = dictionary["ssid"]
let newSSID = ssid + "something I want to edit my values with"
// now we have our new value, so we update the array
dictionaries[i]["ssid"] = newSSID
i += 1
}
now after this we just overwrite the original file with the new dictionaries object, which I wrote out above.

Related

Parsing swift arrays into valid json

So the issue I am facing is that i have two arrays in an ios app which i need to store in a remote mySQL database, which i would like to accomplish using php and json. I haven't, however, despite several days of work, managed to get the arrays in the ios app converted into json code which doesn't crash the app. The arrays are populated by a qr code reader and input field, and there is always an equal amount of items in each array. Currently the code below generates the following json:
json string = {"b":"[\n\n]","p":"[\n\n]"}
No matter what changes i do, the app seems to crash with the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write', or alternatively it says Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.} with some of my other experiments (like the version currently below)
var productArray = [String]()
var amountArray = [String]()
func addTapped(sender: UIBarButtonItem) {
print("Running add func")
do {
var test1 = ""
var test2 = ""
//Convert to Data
let jsonData1 = try! JSONSerialization.data(withJSONObject: amountArray, options: JSONSerialization.WritingOptions.prettyPrinted)
let jsonData2 = try! JSONSerialization.data(withJSONObject: productArray, options: JSONSerialization.WritingOptions.prettyPrinted)
//Convert back to string. Usually only do this for debugging
if let JSONString1 = String(data: jsonData1, encoding: String.Encoding.utf8) {
print(JSONString1)
test1 = JSONString1
}
if let JSONString2 = String(data: jsonData2, encoding: String.Encoding.utf8) {
print(JSONString2)
test2 = JSONString2
}
//In production, you usually want to try and cast as the root data structure. Here we are casting as a dictionary. If the root object is an array cast as [AnyObject].
var json1 = try JSONSerialization.jsonObject(with: jsonData1, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: AnyObject]
var json2 = try JSONSerialization.jsonObject(with: jsonData2, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: AnyObject]
let dict = ["json1": test1, "json2": test2] as [String: Any]
print("All JSON should print below")
print(dict)
if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) {
let url = NSURL(string: "http://www.server.com/receiver")!
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request as URLRequest){ data,response,error in
if error != nil{
print(error?.localizedDescription)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let resultValue:String = parseJSON["success"] as! String;
print("result: \(resultValue)")
print(parseJSON)
}
} catch let error as NSError {
print(error)
}
}
task.resume()
}
} catch {
print("Oops")
}
}
I think the best solution is using SwiftyJSON
Whit that, if you have a String you can use var json = JSON.parse(yourString)

iOS create JSON file as sample data to test network and parsing logic

I'm working with an project dealing with send request to server and get JSON response. Is there a way to create a offline JSON file as sample data so that the app read from sample data file instead of making real network request? I want to test the JSON parsing and mapping before write network call
For example, how can we make a JSON file from this JSON?
{
"by" : "dhouston",
"descendants" : 71,
"id" : 8863,
"kids" : [ 8952, 9224, 8917, 8884, 8887, 8943, 8869, 8958, 9005, 9671, 9067, 8940, 8908, 9055, 8865, 8881, 8872, 8873, 8955, 10403, 8903, 8928, 9125, 8998, 8901, 8902, 8907, 8894, 8878, 8980, 8870, 8934, 8876 ],
"score" : 111,
"time" : 1175714200,
"title" : "My YC app: Dropbox - Throw away your USB drive",
"type" : "story",
"url" : "http://www.getdropbox.com/u/2/screencast.html"
}
use this to serialize, post and get a json back:
let json = ["by":"dhouston","descendants":"71"]
do {
let jsonData = try JSONSerialization.data(withJSONObject: json, options: [])
let url = NSURL(string: "your url")!
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
request.httpBody = jsonData
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request as URLRequest){ data,response,error in
if error != nil{
print(error!.localizedDescription)
return
}
let header = response as! HTTPURLResponse
print(header.allHeaderFields)
do {
let responseObject = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: String] // your json response for example [String: String], depends on what you get as a response
print(responseObject)
// do something
} catch let jsonError {
print(jsonError)
print(String(data: data!, encoding: String.Encoding.utf8)!)
}
}
task.resume()
} catch {
print(error)
}
if you just want to serialize use:
let json = ["by":"dhouston","descendants":"71"]
do {
let jsonData = try JSONSerialization.data(withJSONObject: json, options: [])
} catch {
print(error)
}
Save your json file in your main bundle, then you can read it as json data, followed by parsing:
let filePath = Bundle.main.path(forResource: "jsonfile", ofType: "json")
let data = Data(contentsOf: URL(string: filePath)!)
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)
} catch error {
print(error)
}
Create new file with Strings by Xcode->New->File->String File
Rename file with File.json
Use below code SWIFT 3.x for picking .json file
override func viewDidLoad() {
super.viewDidLoad()
let sampleDataPath = Bundle.main.bundleURL.appendingPathComponent("File.json").path
print(sampleDataPath)
}

How to login by POST method or How to access data by POST method

I am trying to get data from API with multiple parameter and using Headers.
i try a lot but not success, problem is that i can do this using Alamofire. but i want to do it by NSURLSession.
func apiCalling(){
let myUrl = NSURL(string: "http://203.XXXXXXXXX.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";// Compose a query string
request.addValue("KAISAPAISA", forHTTPHeaderField: "APIXXXXX")
let postString = "uname=demo&password=demo123";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil
{
print("error=\(error)")
return
}
// You can print out response object
print("response = \(response)")
// Print out response body
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
//Let's convert response sent from a server side script to a NSDictionary object:
do {
let myJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = myJSON {
// Now we can access value of First Name by its key
let firstNameValue = parseJSON["firstName"] as? String
print("firstNameValue: \(firstNameValue)")
}
} catch {
print(error)
}
}
task.resume()
}

Upload an Image to a RESTful API

hello I am successfully posting data into server but this time I want to upload an image to server. I am using this function to post the data without image
static func postToServer(url:String,params:Dictionary<String,NSObject>,image:String?, completionHandler: (NSDictionary?, String?) -> Void ) -> NSURLSessionTask {
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
if(params["data"] != "get"){
do {
let data = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
let dataString = NSString(data: data, encoding: NSUTF8StringEncoding)!
print("dataString is \(dataString)")
request.HTTPBody = data//try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
} catch {
//handle error. Probably return or mark function as throws
print("error is \(error)")
//return
}
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) {data, response, error -> Void in
// handle error
guard error == nil else { return }
//print("Response: \(response)")
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
completionHandler(nil,"Body: \(strData!)")
//print("Body: \(strData!)")
let json: NSDictionary?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
} catch let dataError {
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
print(dataError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
completionHandler(nil,"Body: \(jsonStr!)")
// return or throw?
return
}
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
completionHandler(parseJSON,nil)
//let success = parseJSON["success"] as? Int
//print("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
completionHandler(nil,"Body: \(jsonStr!)")
}
}
task.resume()
return task
}
Now as I have to send an image now also I think I have to do this
var imageData = UIImageJPEGRepresentation(image, 0.9)
var base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!)
var params = ["image":[ "content_type": "image/jpeg", "filename":"test.jpg", "file_data": base64String]]
now the problem is how can I add these params in the above params variable. I mean right now the format of my params is like this
{
"email" : "hello",
"password" : "hello"
}
Could you not just add them to the params you already have, like this?
var params = ["email":"hello", "password":"hello"]
params["image"] = ["content_type": "image/jpeg", "filename":"test.jpg", "file_data": base64String]

Create and send json data to server using swift language and iOS 9+

I really need a code for send and receive data from server with JSON, i find a really good code but it isn't compatible with iOS9.
#IBAction func submitAction(sender: AnyObject) {
//declare parameter as a dictionary which contains string as key and value combination.
var parameters = ["name": nametextField.text, "password": passwordTextField.text] as Dictionary<String, String>
//create the url with NSURL
let url = NSURL(string: "http://myServerName.com/api") //change the url
//create the session object
var session = NSURLSession.sharedSession()
//now create the NSMutableRequest object using the url object
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST" //set http method as POST
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: &err) // pass dictionary to nsdata object and set it as request body
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume() }
Really thanks for the help
Swift syntax changed a little bit, but not significantly to break the whole code.
You will need to adjust few things like
println(err!.localizedDescription)
to
print(err!.localizedDescription)
Then your code will compile
Maybe have a look into the Alamofire Framework.
It really is making your life easier when it comes to handling HTTP requests.
Otherwise, as vadian suggested, check out the Swift 2 (do-try-catch) Errorhandling.
I have found a great tutorial Project from deege.
https://github.com/deege/deegeu-swift-rest-example
Here a breakdown of a HTTP request.
// Setup the session to make REST GET call. Notice the URL is https NOT http!! (if you need further assistance on how and why, let me know)
let endpoint: String = "https://yourAPI-Endpoint"
let session = NSURLSession.sharedSession()
let url = NSURL(string: endpoint)!
// Make the call and handle it in a completion handler
session.dataTaskWithURL(url, completionHandler: { ( data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
// Make sure we get an OK response
guard let realResponse = response as? NSHTTPURLResponse where
realResponse.statusCode == 200 else {
print("Not a 200 response")
return
}
// Read the JSON
do {
if let jsonString = NSString(data:data!, encoding: NSUTF8StringEncoding) {
// Print what we got from the call
print(jsonString)
// Parse the JSON
let jsonDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
let value = jsonDictionary["key"] as! String
}
} catch {
print("bad things happened")
}
}).resume()

Resources