Connect to an online database (mySQL) from Swift, using PHP. (XCODE) - ios

I want to connect my xcode app to online database and get the data from it and display in my app + write the data into online database using my app. I've already done with app but now it gives me an error.
ERROR :
I have my online database in my web page and i have uploaded two php files into the file manager in my web. One php file retrieving all the data in my database and encoding them to json. And second php file doing the query to write data into my online database from my app.
As in above pic im getting json output successfully but when i try to get the data into an array in xcode it gives me that error.
This is my code
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableview: UITableView!
#IBOutlet var inputFriendName: UITextField!
#IBOutlet var inputFriendInfo: UITextField!
var data: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
data = dataOfJson("http://bishanonline.com/extra/serviceselect.php")
println(data)
}
#IBAction func reload() {
data = dataOfJson("http://bishanonline.com/extra/serviceselect.php")
self.tableview.reloadData()
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func dataOfJson(url: String) -> NSArray {
var data = NSData(contentsOfURL: NSURL(string: url)!)
return (NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as NSArray)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: additionInfoCell = self.tableview.dequeueReusableCellWithIdentifier("customCell") as additionInfoCell
var maindata = (data[indexPath.row] as NSDictionary)
cell.friendName!.text = maindata["Name"] as? String
cell.friendInfo!.text = maindata["Additional Info"] as? String
return cell
}
#IBAction func uploadToDatabase() {
var url: NSString = "http://bishanonline.com/extra/servicequery.php?x=\(inputFriendName.text)&y=\(inputFriendInfo.text)"
url = url.stringByReplacingOccurrencesOfString(" ", withString: "%20")
url = url.stringByReplacingOccurrencesOfString("/n", withString: "%0A")
var data = NSData(contentsOfURL: NSURL(string: url)!)
var result = NSString(data: data!, encoding: NSUTF8StringEncoding)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Issue is in this code lines
func dataOfJson(url: String) -> NSArray {
var data = NSData(contentsOfURL: NSURL(string: url)!)
return (NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as NSArray)
}
Please help me to get json data into array. Appreciate any help.

Finally problem resolved.First i am going to elaborate the exact problem then the solution will be posted.
The code you were doing was totally fine but the real problem was your backend
For serviceselect.php
The code you have done for fetching records is
func dataOfJson(url: String) -> NSArray
{
var data = NSData(contentsOfURL: NSURL(string: url)!)
return (NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as NSArray)
}
This above method is returing NSArray but the data you are getting from the server is kinda messed up because along with JSON data some garbage data is included as well.Check out the below image
So when try to generate JSON data from above string we are getting crashes and errors.
May be due to free hosting service we are getting this message (Not sure)
Solution
func getallrecords(){
let url = NSURL(string: "http://bishanonline.com/extra/serviceselect.php")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
var d = NSString(data: data, encoding: NSUTF8StringEncoding)
var arr = d!.componentsSeparatedByString("<") // spliting the incoming string from "<" operator because before that operator is our required data and storing in array
var dataweneed:NSString = arr[0] as NSString // arr[0] is the data before "<" operator and arr[1] is actually no use for us
if let data = NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSArray
// JSONObjectWithData always have first argument of NSData but our dataweneed is actually NSString so we are actually converting NSString to NSData
{
for dd in data{
var name : String = dd["Name"]! as String
var info : String = dd["Additional Info"]! as String
println("Name is : \(name)") // MainDeveloper for 0 and BestBuddy for 1 index
println("Info is : \(info)") // Bishan for 0 and AkilaPrabath for 1 index
}
}
}
task.resume()
}
Final output
For servicequery.php
func addrecord(x:String,y:String){
let request = NSMutableURLRequest(URL: NSURL(string: "http://bishanonline.com/extra/servicequery.php")!)
var postString : String = "x="+x+"&y="+y
request.HTTPMethod = "GET"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
if jsonResult as String == "Successfully added "
{
// Show an alert to notify user
}
}
task.resume()
}
Also remove "echo $query;" on line 30 of servicequery.php

Try this code to parse JSON from server
//created NSURL
let requestURL = NSURL(string: URL_GET_TEAMS)
//creating NSMutableURLRequest
let request = NSMutableURLRequest(URL: requestURL!)
//setting the method to post
request.HTTPMethod = "GET"
//creating a task to send the post request
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
//exiting if there is some error
if error != nil{
print("error is \(error)")
return;
}
//parsing the response
do {
//converting resonse to NSArray
let myJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray
//looping through all the json objects in the array teams
for i in 0 ..< myJSON.count{
myJSON[i]["object key here"]
}
} catch {
print(error)
}
}
//executing the task
task.resume()
Source: json parsing in ios swift

Related

Invalid value around character 0 swift

I hope you are having a great day. I encountered an error that I did some research about. The error I think means that my JSON object is not a proper one to be serialized by the JSONSerialization class on swift 3.0. I verified that my json object is not valid by using the method .isValidJSONObject of the JSONSerialization class.
I checked that my json object is valid. The error occure at the line where "JSONSerialization.jsonObject" method execute. I would love if you can help me figure out how to solve this problem. Feel free to ask for more code parts or project settings. Thanks in advance.
Here is the code used:
import UIKit
class ViewController: UIViewController, NSURLConnectionDataDelegate {
lazy var receivedData = NSMutableData()
override func viewDidLoad() {
super.viewDidLoad()
var url = NSURL(string:"http://localhost:8080/OurServer/webresources/server")!
var request = NSURLRequest(url: url as URL)
var connection = NSURLConnection(request: request as URLRequest, delegate: self, startImmediately: false)!
connection.start()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func connection(_ connection: NSURLConnection, didReceive data: Data)
{
receivedData.append(data)
var temp1 = receivedData as NSMutableData
do
{
var temp3 = JSONSerialization.isValidJSONObject(receivedData)
var jsonResult = try JSONSerialization.jsonObject(with: receivedData as Data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
print("\n")
print(jsonResult)
}
catch let error as NSError
{
print("\n" + "\(error)")
}
}
}
As mentioned in the comment NSURLConnection is outdated.
This is a modern, Swift 3 compliant version of your code using URLSession
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string:"http://localhost:8080/OurServer/webresources/server")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
print("\n", jsonResult)
} catch {
print("\n", error)
}
}
task.resume()
}
}
After checking, it appears i made a not very smart mistake. The mistake was with my url. excuse me for that guys.

Table only shows when interacting and not by default

I have a table in a view controller that is populated through a dictionary from which information is retrieved via a JSON request. In the viewDidLoad() function, I call the function that retrieves the data which is added to `IncompletedDeadlines dictionary:
override func viewDidLoad() {
super.viewDidLoad()
self.IncompleteDeadlines = [String:AnyObject]()
self.retrieveIncompletedDeadlines()
}
Everything works however the table only shows when interacted with. I thought maybe the best way to show the table the moment the view appears is by adding a tableView.reload to viewDidAppear as so:
override func viewDidAppear(_ animated: Bool) {
self.tableView.reloadData()
}
But this doesn't fix it. I have attached pictures for clarity of the situation. Picture one shows the view the moment the view appears. Picture 2 only happens once the table is interacted with i.e. swiped. So my question is how can I get the table to show immediately? I understand there can be a delay because of the load, but I shouldn't have to interact with it for it to show:
When the view is interacted with i.e. swiped:
The retrieveIncompletedDeadlines() function is as so:
func retrieveIncompletedDeadlines(){
let myUrl = NSURL(string: "https://www.example.com/scripts/retrieveIncompleteDeadlines.php");
let request = NSMutableURLRequest(url:myUrl! as URL)
let user_id = UserDetails[0]
request.httpMethod = "POST";
let postString = "user_id=\(user_id)";
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
}
var err: NSError?
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let checker:String = parseJSON["status"] as! String;
if(checker == "Success"){
let resultValue = parseJSON["deadlines"] as! [String:AnyObject]
self.IncompleteDeadlines = resultValue
}
self.tableView.reloadData()
}
} catch let error as NSError {
err = error
print(err!);
}
}
task.resume();
self.tableView.reloadData()
}
JSON will be parsed on the background thread but any update to the UI must be done on the main thread hence you have to do it inside DispatchQueue.main.async {} This article explains well what is the problem.
Furthermore I would write a completions handler which returns the data once the operation has finished. This is another interesting article about.
Completion handlers are super convenient when your app is doing something that might take a little while, like making an API call, and you need to do something when that task is done, like updating the UI to show the data.
var incompleteDeadlines = [String:AnyObject]()
override func viewDidLoad() {
super.viewDidLoad()
//please note your original function has changed
self.retrieveIncompletedDeadlines { (result, success) in
if success {
// once all the data has been parsed you assigned the result to self.incompleteDeadlines
self.incompleteDeadlines = result
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
func retrieveIncompletedDeadlines(_ completion:#escaping ([String:AnyObject] , _ success: Bool)-> Void){
let myUrl = NSURL(string: "https://www.example.com/scripts/retrieveIncompleteDeadlines.php");
let request = NSMutableURLRequest(url:myUrl! as URL)
let user_id = UserDetails[0]
request.httpMethod = "POST";
let postString = "user_id=\(user_id)";
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
}
var err: NSError?
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let checker:String = parseJSON["status"] as! String;
var resultValue = [String:AnyObject]()
if(checker == "Success"){
resultValue = parseJSON["deadlines"] as! [String:AnyObject]
}
completion(resultValue, true)
}
} catch let error as NSError {
err = error
print(err!);
}
}
task.resume();
}
}

Show JSON data in a TableView with Swift

I am trying to display some data I take from a data base into a TableView but the data is not shown in the TableView. The data I receive is formatted in JSON.
This is the data I receive form the data base and what I want to print in the TableViewis just David:
{"name":"David"}
This is the code to get the data from de data base:
let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: NSURL(string: "http://localhost:8888/Patients.php")!)
let task = session.dataTaskWithRequest(request) {data, response, downloadError in
if let error = downloadError {
print("Could not complete the request \(error)")
}
else {
do {
self.json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
} catch {
fatalError()
}
dispatch_async(dispatch_get_main_queue(), {
if let parseJSON = self.json{
let name = parseJSON["name"] as! String
self.arrayData.append(name)
print("Data1:\(self.arrayData)")
}
})
}
}
task.resume()
arrayData is an array where I put the data I receive from the data base and it is declared like this:
var arrayData: [String] = []
The code
print("Data1:\(self.arrayData)")
show in the console this Data1:["David"], so I get the data correctly.
Then I implement the methods to print in the ´TableView´, the numberOfSectionsInTableViewmethod, the numberOfRowsInSection method and the cellForRowAtIndexPath method but the data is not printed in the TableView.
I think the problem is that the TableViewis drawn before I put the data in the array so it prints nothing because the array is empty, and I don´t know how to fix it.
Anyone knows what is my problem?
yes, you're right.
session.dataTaskWithRequest
is async. Data is not returned immediately, it have delay.
You must to reload tableview after recieved data:
self.arrayData.append(name)
self.tableview.reloadData()
Usually i will use block:
func getData(handleComplete:((arr:NSMutableArray)->())){
let aray = NSMutableArray()
let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: NSURL(string: "http://localhost:8888/Patients.php")!)
let task = session.dataTaskWithRequest(request) {data, response, downloadError in
if let error = downloadError {
print("Could not complete the request \(error)")
}
else {
do {
self.json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
} catch {
fatalError()
}
dispatch_async(dispatch_get_main_queue(), {
if let parseJSON = self.json{
let name = parseJSON["name"] as! String
aray.append(name)
print("Data1:\(self.arrayData)")
}
handleComplete(aray)
})
}
}
task.resume()
arrayData
}
and in viewdidload i will call:
override func viewDidLoad() {
super.viewDidLoad()
self.getData { (arr) -> () in
self.tableview.reloadData()
}
}
it 's better

SwiftyJSON Problems

I am trying to extract some data out of a JSON object I am pulling in from Reddit, and am having issues when using the SwiftyJSON library (you can find this here: https://github.com/SwiftyJSON/SwiftyJSON).
I am calling Reddit's API at the following URL, "http://www.reddit.com/r/aww/hot.json" I am trying to extract a few key value pairs out of the json response, starting with the author of a listing.
My code is below:
import UIKit
class ViewController: UIViewController, NSURLConnectionDelegate {
var data = NSMutableData()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.connectReddit()
}
func connectReddit() {
let urlPath: String = "http://www.reddit.com/r/aww/hot.json"
var url = NSURL(string: urlPath)!
var request = NSURLRequest(URL: url)
var connection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
self.data.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
var err: NSError?
// throwing an error on the line below (can't figure out where the error message is)
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
println(jsonResult)
let json = JSON(data: data)
let authorName = json["data"]["children"]["author"].stringValue
println(authorName)
}
}
You can see the code calling the SwifyJSON class, trying to parse it for data is the following, I am getting nil as a response when I clearly see data there.
let json = JSON(data: data)
let authorName = json["data"]["children"]["author"].stringValue
println(authorName)
I am not sure what I am doing wrong here.
Thanks for the help!
you should try this ;
let authorName = json["data"]["children"][0]["data"]["author"].stringValue
For Swift 3.0.1:
let authorName = json["data"]["children"][0]["data"]["author"].string

How to parse a JSON file in swift?

I have a JSON file, want to parse and use list of objects in table view. Can any one share the code to parse JSON file in swift.
This answer was last revised for Swift 5.3 and iOS 14.4 SDK.
Given some already obtained JSON data, you can use JSONDecoder to decode it into your Decodable model (or a collection of models).
let data: Data = /* obtain your JSON data */
let model = try JSONDecoder().decode(Model.self, from: data)
Such model must conform to the Decodable protocol and contain correct mapping between properties and JSON dictionary keys. As an example, consider the following JSON array containing search results of cities beginning with "Wa".
[
{
"id": 123,
"city": "Washington",
"region": "D.C.",
"country": "United States"
},
{
"id": 456,
"city": "Warsaw",
"region": "Mazowieckie",
"country": "Poland"
},
...
]
For that, you need to create a model that contains the correct properties of correct types. If you're using a web API, its documentation will be of great help here.
struct SearchResult: Decodable {
let id: Int
let city: String
let region: String
let country: String
}
Then decode the data with JSONDecoder:
let results = try JSONDecoder().decode([SearchResult].self, from: data)
Given a new array of decoded search results, call one of UITableView's functions to reload its data. Note that the decode function can throw an error which you must somehow handle.
To learn more about decoding custom types in Swift and more advanced usage of the Codable APIs, I recommend checking out this documentation article.
Making the API Request
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)
Preparing for the response
Declare an array as below
var data: NSMutableData = NSMutableData()
Receiving the response
1.
func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
// Received a new request, clear out the data object
self.data = NSMutableData()
}
2.
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
// Append the received chunk of data to our data object
self.data.appendData(data)
}
3.
func connectionDidFinishLoading(connection: NSURLConnection!) {
// Request complete, self.data should now hold the resulting info
// Convert the retrieved data in to an object through JSON deserialization
var err: NSError
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
if jsonResult.count>0 && jsonResult["results"].count>0 {
var results: NSArray = jsonResult["results"] as NSArray
self.tableData = results
self.appsTableView.reloadData()
}
}
When NSURLConnection receives a response, we can expect the didReceiveResponse method to be called on our behalf. At this point we simply reset our data by saying self.data = NSMutableData(), creating a new empty data object.
After a connection is made, we will start receiving data in the method didReceiveData. The data argument being passed in here is where all our juicy information comes from. We need to hold on to each chunk that comes in, so we append it to the self.data object we cleared out earlier.
Finally, when the connection is done and all data has been received, connectionDidFinishLoading is called and we’re ready to use the data in our app. Hooray!
The connectionDidFinishLoading method here uses the NSJSONSerialization class to convert our raw data in to useful Dictionary objects by deserializing the results from your Url.
I just wrote a class called JSON, which makes JSON handling in Swift as easy as JSON object in ES5.
https://github.com/dankogai/swift-json/
Turn your swift object to JSON like so:
let obj:[String:AnyObject] = [
"array": [JSON.null, false, 0, "",[],[:]],
"object":[
"null": JSON.null,
"bool": true,
"int": 42,
"double": 3.141592653589793,
"string": "a α\t弾\n𪚲",
"array": [],
"object": [:]
],
"url":"http://blog.livedoor.com/dankogai/"
]
let json = JSON(obj)
json.toString()
...or string...
let json = JSON.parse("{\"array\":[...}")
...or URL.
let json = JSON.fromURL("http://api.dan.co.jp/jsonenv")
Tree Traversal
Just traverse elements via subscript:
json["object"]["null"].asNull // NSNull()
// ...
json["object"]["string"].asString // "a α\t弾\n𪚲"
json["array"][0].asNull // NSNull()
json["array"][1].asBool // false
// ...
Just like SwiftyJSON you don't worry if the subscripted entry does not exist.
if let b = json["noexistent"][1234567890]["entry"].asBool {
// ....
} else {
let e = json["noexistent"][1234567890]["entry"].asError
println(e)
}
If you are tired of subscripts, add your scheme like so:
//// schema by subclassing
class MyJSON : JSON {
init(_ obj:AnyObject){ super.init(obj) }
init(_ json:JSON) { super.init(json) }
var null :NSNull? { return self["null"].asNull }
var bool :Bool? { return self["bool"].asBool }
var int :Int? { return self["int"].asInt }
var double:Double? { return self["double"].asDouble }
var string:String? { return self["string"].asString }
}
And you go:
let myjson = MyJSON(obj)
myjson.object.null
myjson.object.bool
myjson.object.int
myjson.object.double
myjson.object.string
// ...
Hope you like it.
With the new xCode 7.3+ its important to add your domain to the exception list (How can I add NSAppTransportSecurity to my info.plist file?), refer to this posting for instructions, otherwise you will get a transport authority error.
Codable
In Swift 4+ is strongly recommended to use Codable instead of JSONSerialization.
This Codable includes two protocols: Decodable and Encodable. This Decodable protocol allows you to decode Data in JSON format to custom struct/class conforming to this protocol.
For example imagine situation that we have this simple Data (array of two objects)
let data = Data("""
[
{"name":"Steve","age":56},
{"name":"iPhone","age":11}
]
""".utf8)
then have following struct and implement protocol Decodable
struct Person: Decodable {
let name: String
let age: Int
}
now you can decode your Data to your array of Person using JSONDecoder where first parameter is type conforming to Decodable and to this type should Data be decoded
do {
let people = try JSONDecoder().decode([Person].self, from: data)
} catch { print(error) }
... note that decoding has to be marked with try keyword since you could for example make some mistake with naming and then your model can't be decoded correctly ... so you should put it inside do-try-catch block
Cases that key in json is different from name of property:
If key is in named using snake_case, you can set decoder's keyDecodingStrategy to convertFromSnakeCase which changes key from property_name to camelCase propertyName
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let people = try decoder.decode([Person].self, from: data)
If you need unique name you can use coding keys inside struct/class where you declare name of key
let data = Data("""
{ "userName":"Codable", "age": 1 }
""".utf8)
struct Person: Decodable {
let name: String
let age: Int
enum CodingKeys: String, CodingKey {
case name = "userName"
case age
}
}
Here is a code to make the conversions between JSON and NSData in Swift 2.0
// Convert from NSData to json object
func nsdataToJSON(data: NSData) -> AnyObject? {
do {
return try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers)
} catch let myJSONError {
print(myJSONError)
}
return nil
}
// Convert from JSON to nsdata
func jsonToNSData(json: AnyObject) -> NSData?{
do {
return try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted)
} catch let myJSONError {
print(myJSONError)
}
return nil;
}
Install Swifty Json
Note: if you are looking for this, there's also a high chance you don't know how to install swifty. Follow the instructions here.
sudo gem install cocoapods
cd ~/Path/To/Folder/Containing/ShowTracker
Next enter this command:
pod init
This will create a default Podfile for your project. The Podfile is where you define the dependencies your project relies on.
Type this command to open Podfile using Xcode for editing:
open -a Xcode Podfile
Add the Swifty into the podfile
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
pod 'SwiftyJSON', '~> X.X.X'
end
Check this example
var mURL = NSURL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&units=metric")
if mURL == nil{
println("You are stupid")
return
}
var request = NSURLRequest(URL: mURL!)
NSURLConnection.sendAsynchronousRequest(
request,
queue: NSOperationQueue.mainQueue(),
completionHandler:{ (
response: NSURLResponse!,
data: NSData!,
error: NSError!) -> Void in
if data != nil {
var mJSON = JSON(data: data!)
if let current_conditions = mJSON["weather"][0]["description"].string {
println("Current conditions: " + current_conditions)
} else {
println("MORON!")
}
if let current_temperature = mJSON["main"]["temp"].double {
println("Temperature: "+ String(format:"%.f", current_temperature) + "°C"
} else {
println("MORON!")
}
}
})
I also wrote a small library which is specialized for the mapping of the json response into an object structure. I am internally using the library json-swift from David Owens. Maybe it is useful for someone else.
https://github.com/prine/ROJSONParser
Example Employees.json
{
"employees": [
{
"firstName": "John",
"lastName": "Doe",
"age": 26
},
{
"firstName": "Anna",
"lastName": "Smith",
"age": 30
},
{
"firstName": "Peter",
"lastName": "Jones",
"age": 45
}]
}
As next step you have to create your data model (EmplyoeeContainer and Employee).
Employee.swift
class Employee : ROJSONObject {
required init() {
super.init();
}
required init(jsonData:AnyObject) {
super.init(jsonData: jsonData)
}
var firstname:String {
return Value<String>.get(self, key: "firstName")
}
var lastname:String {
return Value<String>.get(self, key: "lastName")
}
var age:Int {
return Value<Int>.get(self, key: "age")
}
}
EmployeeContainer.swift
class EmployeeContainer : ROJSONObject {
required init() {
super.init();
}
required init(jsonData:AnyObject) {
super.init(jsonData: jsonData)
}
lazy var employees:[Employee] = {
return Value<[Employee]>.getArray(self, key: "employees") as [Employee]
}()
}
Then to actually map the objects from the JSON response you only have to pass the data into the EmployeeContainer class as param in the constructor. It does automatically create your data model.
var baseWebservice:BaseWebservice = BaseWebservice();
var urlToJSON = "http://prine.ch/employees.json"
var callbackJSON = {(status:Int, employeeContainer:EmployeeContainer) -> () in
for employee in employeeContainer.employees {
println("Firstname: \(employee.firstname) Lastname: \(employee.lastname) age: \(employee.age)")
}
}
baseWebservice.get(urlToJSON, callback:callbackJSON)
The console output looks then like the following:
Firstname: John Lastname: Doe age: 26
Firstname: Anna Lastname: Smith age: 30
Firstname: Peter Lastname: Jones age: 45
SwiftJSONParse: Parse JSON like a badass
Dead-simple and easy to read!
Example: get the value "mrap" from nicknames as a String from this JSON response
{
"other": {
"nicknames": ["mrap", "Mikee"]
}
It takes your json data NSData as it is, no need to preprocess.
let parser = JSONParser(jsonData)
if let handle = parser.getString("other.nicknames[0]") {
// that's it!
}
Disclaimer: I made this and I hope it helps everyone. Feel free to improve on it!
Parsing JSON in Swift is an excellent job for code generation. I've created a tool at http://www.guideluxe.com/JsonToSwift to do just that.
You supply a sample JSON object with a class name and the tool will generate a corresponding Swift class, as well as any needed subsidiary Swift classes, to represent the structure implied by the sample JSON. Also included are class methods used to populate Swift objects, including one that utilizes the NSJSONSerialization.JSONObjectWithData method. The necessary mappings from the NSArray and NSDictionary objects are provided.
From the generated code, you only need to supply an NSData object containing JSON that matches the sample provided to the tool.
Other than Foundation, there are no dependencies.
My work was inspired by http://json2csharp.com/, which is very handy for .NET projects.
Here's how to create an NSData object from a JSON file.
let fileUrl: NSURL = NSBundle.mainBundle().URLForResource("JsonFile", withExtension: "json")!
let jsonData: NSData = NSData(contentsOfURL: fileUrl)!
Swift 3
let parsedResult: [String: AnyObject]
do {
parsedResult = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:AnyObject]
} catch {
// Display an error or return or whatever
}
data - it's Data type (Structure) (i.e. returned by some server response)
The entire viewcontroller which show data in collecction view using two methods of json parsig
#IBOutlet weak var imagecollectionview: UICollectionView!
lazy var data = NSMutableData()
var dictdata : NSMutableDictionary = NSMutableDictionary()
override func viewDidLoad() {
super.viewDidLoad()
startConnection()
startNewConnection()
// Do any additional setup after loading the view, typically from a nib.
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dictdata.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CustomcellCollectionViewCell", forIndexPath: indexPath) as! CustomcellCollectionViewCell
cell.name.text = dictdata.valueForKey("Data")?.valueForKey("location") as? String
let url = NSURL(string: (dictdata.valueForKey("Data")?.valueForKey("avatar_url") as? String)! )
LazyImage.showForImageView(cell.image, url:"URL
return cell
}
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let kWhateverHeightYouWant = 100
return CGSizeMake(self.view.bounds.size.width/2, CGFloat(kWhateverHeightYouWant))
}
func startNewConnection()
{
let url: URL = URL(string: "YOUR URL" as String)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "GET" //set the get or post according to your request
// request.cachePolicy = NSURLRequest.CachePolicy.ReloadIgnoringCacheData
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest) {
( data, response, error) in
guard let _:NSData = data as NSData?, let _:URLResponse = response, error == nil else {
print("error")
return
}
let jsonString = NSString(data: data!, encoding:String.Encoding.utf8.rawValue) as! String
}
task.resume()
}
func startConnection(){
let urlPath: String = "your URL"
let url: NSURL = NSURL(string: urlPath)!
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
self.data.appendData(data)
}
func buttonAction(sender: UIButton!){
startConnection()
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
do {
let JSON = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions(rawValue: 0))
guard let JSONDictionary :NSDictionary = JSON as? NSDictionary else {
print("Not a Dictionary")
// put in function
return
}
print("JSONDictionary! \(JSONDictionary)")
dictdata.setObject(JSONDictionary, forKey: "Data")
imagecollectionview.reloadData()
}
catch let JSONError as NSError {
print("\(JSONError)")
} }
Using ObjectMapper framework
if let path = Bundle(for: BPPView.self).path(forResource: jsonFileName, ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: NSData.ReadingOptions.mappedIfSafe)
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
self.levels = Mapper<Level>().mapArray(JSONArray: (json as! [[String : Any]]))!
print(levels.count)
} catch let error as NSError {
print(error.localizedDescription)
}
} else {
print("Invalid filename/path.")
}
Before you should prepare the set of appropriate :Mappable objects to parse into
import UIKit
import ObjectMapper
class Level: Mappable {
var levelName = ""
var levelItems = [LevelItem]()
required init?(map: Map) {
}
// Mappable
func mapping(map: Map) {
levelName <- map["levelName"]
levelItems <- map["levelItems"]
}
import UIKit
import ObjectMapper
class LevelItem: Mappable {
var frontBackSide = BPPFrontBack.Undefined
var fullImageName = ""
var fullImageSelectedName = ""
var bodyParts = [BodyPart]()
required init?(map: Map) {
}
// Mappable
func mapping(map: Map) {
frontBackSide <- map["frontBackSide"]
fullImageName <- map["fullImageName"]
fullImageSelectedName <- map["fullImageSelectedName"]
bodyParts <- map["bodyParts"]
}}
Swift 4 API Request Example
Make use of JSONDecoder().decode
See this video JSON parsing with Swift 4
struct Post: Codable {
let userId: Int
let id: Int
let title: String
let body: String
}
URLSession.shared.dataTask(with: URL(string: "https://jsonplaceholder.typicode.com/posts")!) { (data, response, error) in
guard let response = response as? HTTPURLResponse else {
print("HTTPURLResponse error")
return
}
guard 200 ... 299 ~= response.statusCode else {
print("Status Code error \(response.statusCode)")
return
}
guard let data = data else {
print("No Data")
return
}
let posts = try! JSONDecoder().decode([Post].self, from: data)
print(posts)
}.resume()
This parser uses generics to cast JSON to Swift types which reduces the code you need to type.
https://github.com/evgenyneu/JsonSwiftson
struct Person {
let name: String?
let age: Int?
}
let mapper = JsonSwiftson(json: "{ \"name\": \"Peter\", \"age\": 41 }")
let person: Person? = Person(
name: mapper["name"].map(),
age: mapper["age"].map()
)
Below is a Swift Playground example:
import UIKit
let jsonString = "{\"name\": \"John Doe\", \"phone\":123456}"
let data = jsonString.data(using: .utf8)
var jsonObject: Any
do {
jsonObject = try JSONSerialization.jsonObject(with: data!) as Any
if let obj = jsonObject as? NSDictionary {
print(obj["name"])
}
} catch {
print("error")
}
Swift 4
Create a Project
Design StoryBoard With a Button and a UITableview
Create TableViewCell VC
In Button Action Insert the folloeing Codes
Remember This Code for Fetch Array of Data in an Api
import UIKit
class ViewController3: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var displayDatasssss = [displyDataClass]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return displayDatasssss.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell1") as! TableViewCell1
cell.label1.text = displayDatasssss[indexPath.row].email
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func gettt(_ sender: Any) {
let url = "http://jsonplaceholder.typicode.com/users"
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request){(data, response,error)in
if (error != nil){
print("Error")
}
else{
do{
// Array of Data
let fetchData = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as! NSArray
for eachData in fetchData {
let eachdataitem = eachData as! [String : Any]
let name = eachdataitem["name"]as! String
let username = eachdataitem["username"]as! String
let email = eachdataitem["email"]as! String
self.displayDatasssss.append(displyDataClass(name: name, username: username,email : email))
}
self.tableView.reloadData()
}
catch{
print("Error 2")
}
}
}
task.resume()
}
}
class displyDataClass {
var name : String
var username : String
var email : String
init(name : String,username : String,email :String) {
self.name = name
self.username = username
self.email = email
}
}
This is for Dictionary data Fetching
import UIKit
class ViewController3: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var displayDatasssss = [displyDataClass]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return displayDatasssss.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell1") as! TableViewCell1
cell.label1.text = displayDatasssss[indexPath.row].email
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func gettt(_ sender: Any) {
let url = "http://jsonplaceholder.typicode.com/users/1"
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request){(data, response,error)in
if (error != nil){
print("Error")
}
else{
do{
//Dictionary data Fetching
let fetchData = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as! [String: AnyObject]
let name = fetchData["name"]as! String
let username = fetchData["username"]as! String
let email = fetchData["email"]as! String
self.displayDatasssss.append(displyDataClass(name: name, username: username,email : email))
self.tableView.reloadData()
}
catch{
print("Error 2")
}
}
}
task.resume()
}
}
class displyDataClass {
var name : String
var username : String
var email : String
init(name : String,username : String,email :String) {
self.name = name
self.username = username
self.email = email
}
}
Swift 2 iOS 9
let miadata = NSData(contentsOfURL: NSURL(string: "https://myWeb....php")!)
do{
let MyData = try NSJSONSerialization.JSONObjectWithData(miadata!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
print(".........\(MyData)")
}
catch let error as NSError{
// error.description
print(error.description)
}
Swift 5+ & Xcode 13 Working example
Json response
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
]
Model class
struct PostsModel : Decodable {
let userId : Int?
let id : Int?
let title : String?
let body : String?
}
Fetch Response
let url = URL(string: K.GET_POSTS)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let safeData = data,
let response = response as? HTTPURLResponse,
error == nil else { // check for fundamental networking error
print("error", error ?? "Unknown error")
delegate?.onError(error!)
return
}
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
let responseString = String(data: safeData, encoding: .utf8)
do {
let decoder = JSONDecoder()
let loginResponseModel = try decoder.decode([PostsModel].self, from: data!)
}
catch {
print(error)
}
print("responseString = \(responseString)")
}
task.resume()

Resources