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
Related
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.
I have a server for storing username and password data in my application. When testing the app I had everything save to the device locally using NSDefaults, but now that the app is close to being fully launched, I am trying to save them to the server instead, as it is safer that way for the user's information.
When I had it save to NSDefaults, it was easy and short work. Now however, I am trying to POST the data to the server and keep getting build errors. What do I need to change for this to work? Am I not fully understanding how POST and GET works? Thanks. Using Swift 2 as of right now, not my choice, I prefer 3, but my boss isn't letting us update it yet.
The current error is coming from the POST USER DATA TO SERVER section, where xcode claims that userNmeTxt cannot be converted into NSData. Thank you in advance.
EDIT: Error is on line 87: "Cannot convert value of type UITextField! to expected argument type NSData!"
import UIKit
class UserNameViewController: AuthorizationViewController {
#IBOutlet weak var userNameTxt: UITextField!
#IBOutlet weak var continueBtn: UIButton!
var userModel: ProfileModel!
//MARK: - SYSTEMS METHODS
override func viewDidLoad() {
super.viewDidLoad()
userNameTxt.delegate = self
userNameTxt.autocapitalizationType = .Sentences
setEnabledButton()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBarHidden = false
self.navigationItem.leftBarButtonItem = getBackButton()
self.title = ""
}
override func viewWillDisappear(animated: Bool) {
self.navigationController?.navigationBarHidden = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
continueBtn.layer.cornerRadius = 10
}
override func popToRoot(sender:UIBarButtonItem){
self.navigationController!.popViewControllerAnimated(true)
}
//MARK: - CHECK FOR AVALABILITY
func setEnabledButton(){
if userNameTxt.text == "" {
continueBtn.backgroundColor = UIColor.lightGrayColor()
} else {
continueBtn.backgroundColor = UIColor(colorLiteralRed: 63.0/255.0, green: 220.0/255.0, blue: 236.0/255.0, alpha: 1.0)
}
continueBtn.userInteractionEnabled = userNameTxt.text != ""
}
//MARK: - POST USER DATA TO SERVER
func postData(url: String, params: Dictionary<String, String>, completionHandler: (data: NSData?, response: NSURLResponse?, error: NSError?) -> ()) {
// Indicate download
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let url = NSURL(string: "myPlaceholderURLgoesHere")!
// print("URL: \(url)")
let request = NSMutableURLRequest(URL: url)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// Verify downloading data is allowed
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
} catch let error as NSError {
print("Error in request post: \(error)")
request.HTTPBody = nil
} catch {
print("Catch all error: \(error)")
}
// Post the data
let task = session.dataTaskWithRequest(request) { data, response, error in
completionHandler(data: userNameTxt, response: userModel, error: error)
// Stop download indication
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
// Stop download indication
}
task.resume()
}
//MARK: - SEGUE
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toPassword"{
let controller = segue.destinationViewController as! PasswordViewController
controller.userModel = userModel
}
}
//MARK: - IB ACTIONS
#IBAction func continuePressed(sender: AnyObject) {
userModel.userNickName = userNameTxt.text!
performSegueWithIdentifier("toPassword", sender: self)
}
}
extension UserNameViewController: UITextFieldDelegate{
func textFieldDidEndEditing(textField: UITextField) {
self.setEnabledButton()
}
}
There are a couple of things you need to change.
userNameTxt is not the username, it's the UITextField containing the username. The text you need is userNameTxt.text?
If the function is expecting Data, you have to convert your text to Data first
let task = session.dataTaskWithRequest(request) { data, response, error in
completionHandler(data: userNameTxt.text?.data(using: .utf8), response: userModel, error: error)
I assume you have to send the data to the server.
If you don't have too you can save the data in keychain access, see: SO: Keychain Access
In order to resolve the error please edit the question with the error message and line of code (if possible).
I would suggest that you use Alamofire for POST/GET (REST). To use Alamofire you need basic knowledge of Cocoapods. It's better in the long term.
NOTE: There can be two possible error outcomes when you make the request.
1) Incorrect data format or bug from your side
2) Server error due backend bug from server side.
The data can be sent from your device with POST where the data is in the BODY or HEADER of the request. Usually it is in the body (parameters in the alamofire methods).
Here is an example:
import Alamofire
...
// MARK:- Login Feature - Universal Met for login
internal static func loginWith(serverUrl: String, parameters: [String: AnyObject]?, headers: [String: String]?, notificationName: String, serviceType: LoginService)
{
Alamofire.request(.POST, serverUrl, parameters: parameters, headers: headers).responseJSON
{ (response) in
print("\n Login feature - \n")
print(" Login url - \(serverUrl)\n")
print(" Login parameters - \(parameters)\n")
print(" Login notificationName - \(notificationName)\n")
print(" Login response - \(response)\n")
EXCDataParserH.parseResponseFrom(ServiceType.Login(type: serviceType),
operation: nil,
data: response.data,
notification: notificationName)
}
}
Instead of writing the whole thing every time you make a server request, try to do as follows:
import Foundation
import SystemConfiguration
class HTTPHelper{
class func httpPostDataDic(postURL:NSURL,postString:NSString,completionHandler:#escaping (NSDictionary?, NSError?) -> Void ) -> URLSessionTask{
var responseResultData: NSDictionary = NSDictionary()
let request = NSMutableURLRequest(url:postURL as URL);
request.httpMethod = "POST";// Compose a query string
request.httpBody = postString.data(using: String.Encoding.utf8.rawValue);
print(request)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil
{
print("error=\(error)")
completionHandler(nil, error as NSError?)
return
}
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
if let responseString = responseString {
print("responseString = \(responseString)")
}
do {
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
responseResultData=myJSON!
completionHandler(responseResultData, nil)
} catch {
print(error)
}
}
task.resume()
return task
}
}
Now whenever you need to make a server POST request,in your ViewController class, do as follows:
//Requesting server
func requestServer() -> Void{
let postvariable = "Value"
let url = URL(string: "your url")!
let postString = "postkey=\(postvariable)"
HTTPHelper.httpPostDataDic(postURL: url as NSURL, postString: postString) {
(responseResult, error) -> Void in
DispatchQueue.main.async {
if error != nil{
print(error ?? "unknown")
}
else{
print(responseResult ?? "unknown result")
//Parse your response
self.parseResult(result: responseResult!);
}
}
}
}
May I ask you one thing that I didn't understand in your question.
How exactly would you save the login credentials in a server? I mean, if you save the login credentials in the server, how would you authenticate user access to these saved credentials?
Can't figure out why this don't work...
when i run it, i have this error in the console:
[CONNECTION] OK, data correctly downloaded
[ERROR] An error has happened with parsing of json data
nil
maybe is the JSON format in the link that i pass in the salvaJson() function.
This is the viewController:
//MARK:proprietà
#IBOutlet weak var meteoLabel: UILabel!
#IBOutlet weak var descrizioneLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let data = salvaJson()
let json = json_parseData(data!)
print(json)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func salvaJson()->NSData?{
guard let url = NSURL(string: "http://www.medialweb.it/corsi_ok.json") else {
return nil
}
guard let data = NSData(contentsOfURL: url) else {
print("[ERROR] There is an unspecified error with the connection")
return nil
}
print("[CONNECTION] OK, data correctly downloaded")
return data
}
// funzione per la generazione del json a partire da un NSData
func json_parseData(data: NSData) -> NSDictionary? {
do {
let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
print("[JSON] OK!")
return (json as? NSDictionary)
} catch _ {
print("[ERROR] An error has happened with parsing of json data")
return nil
}
}
I have removed the comment at the top o JSON. json_parseData()
Now print:[JSON] OK! but i still have nil instead of the printend json
Problem is your JSON cause json result must be start with array
I tested your code it is working code :
guard let url = NSURL(string: "http://pokeapi.co/api/v2/pokemon/1/") else {
return nil
}
Pokemon Webapi and test your json format
UPDATE :
how can i print the error?
do {
let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
print("[JSON] OK!")
return (json as? NSDictionary)
} catch {
//print("[ERROR] An error has happened with parsing of json data")
print("\(error)")
return nil
}
The JSON doesn't seem to be valid. Here you can find a JSON validator that fails with the URL you have.
agree with Above, you have to make sure your JSON data is in valid format. Try to remove these lines in your JSON data
/**
Export to JSON plugin for PHPMyAdmin
#version 0.1
*/
// Database 'convegnoagi2016_it_db'
// convegnoagi2016_it_db.v_prenotazioni_workshop
#IBOutlet var nameLabel : UILabel!
var finalString: String = "test"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func helloWorldAction(nameTextField: UITextField) {
//fetch data from server
let request = NSMutableURLRequest(URL: NSURL(string: "http://192.168.1.11")!)
request.HTTPMethod = "POST"
let postString = "user=test&pass=test3"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
//error handeling
if error != nil {
println("error=\(error)")
return
}
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
self.finalString = String(responseString!)
println("\(self.finalString)");
}
task.resume()
//print finalString
println("finalString = \(finalString)")
}
}
I am trying to do two things, and I will tell you what isn't working with both.
First, not seen in this code, I was trying to assign a UILabel.text a value, that didn't work at all. I couldn't do it within the function and neither could I do it outside. This brings me to problem number two. When finalString is printed inside the function it outputs the proper value.
However, when its printed outside the function it prints the value it was first assigned. Please tell me how to assign the UILabel.text a value properly and how to use the output outside of the scope of the questions.
Thanks in advance.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameLabel: UITextField!
// you have to add a completion block to your asyncronous request
func fireRequest(link:String,completion: ((data: NSData?) -> Void)) {
if let requestUrl = NSURL(string: link){
let request = NSMutableURLRequest(URL: requestUrl)
request.HTTPMethod = "POST"
let postString = "user=test&pass=test3"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
completion(data: NSData(data: data))
if let error = error {
println("error=\(error)")
return
}
}.resume()
}
}
override func viewDidLoad() {
super.viewDidLoad()
println("Fired request" + NSDate().description )
fireRequest("http://192.168.1.11") { data in
dispatch_async(dispatch_get_main_queue()) {
println("Finished request")
if let data = data { // unwrap your data (!= nil)
let myResponseStr = NSString(data: data, encoding: NSUTF8StringEncoding) as String
self.nameLabel.text = myResponseStr
println("response:"+myResponseStr)
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
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