Trouble unwrapping JSON Array to a String Value - ios

I have been struggling with JSON for a few days. I am trying to create a POST request to my web server for a username, that will return information on said user. I have managed to get the JSON response two ways, but I cannot cast any of the elements of the Array to a string. I am using the SWIFTYJSON API too.
import UIKit
import Foundation
class ViewController: UIViewController {
var token = "barrymanilow"
var endPoint = "http://www.never.money/simple_app7.php"
#IBOutlet weak var firstLabel: UILabel!
override func viewDidLoad() {
submitAction(self)
}
func submitAction(sender: AnyObject) {
let myUrl = NSURL(string: "http://www.mindyour.money/simple_app7.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
// Compose a query string
let postString = "token=\(token)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
if error != nil{
println("error=\(error)")
return
}
// Print out response body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
//Let's convert response sent from a server side script to a NSDictionary object:
var err: NSError?
var myJSON = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error:&err) as? NSArray
var json : JSON = JSON(data: data)
let results: AnyObject? = myJSON?.valueForKey("player_username")
println("\(results)")
let result2 = json["player_username"].string
}
task.resume()
}
}
However, this doesn't seem to be working, can anybody help me?

I see that when using NSJSONSerialization you're casting your JSON response as an NSArray, so for example to get the first item's player_username with SwiftyJSON you would do:
let result2 = json[0]["player_username"].string
It should work without casting json[0] to a dictionary first because thanks to SwiftyJSON the compiler knows that json[0] is a dictionary.
If for some reason json[0] is not automatically subscriptable, you can do:
let playerOneDic = json[0].dictionary
let result2 = playerOneDic["player_username"].string
Otherwise, without SwiftyJSON, you would have to do something like this:
if let playerOne = myJSON?[0] as? [String:AnyObject] {
if let username = playerOne["player_username"] as? String {
println(username)
}
}

Related

How to use access token from response using swift 3

So am making a login application that sends username and password, and the server replies with access token....am trying to save this token for later use but i really cant. here is my code, and the server response incase you need it
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var PhoneNumber: UITextField!
#IBOutlet weak var Password: UITextField!
//***************************************LogIn**********************************************\\
#IBAction func Login(_ sender: UIButton) {
guard let url = URL(string: "https://goollyapp.azurewebsites.net/Token") else {return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString = "username=" + PhoneNumber.text! + "&password="+Password.text!+"&grant_type=password"
print(postString)
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let response = response {
print(response)
}
}
task.resume()
}
}
Where you declare the json variable replace with:
let json = try? JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
Then you can access the token with:
let token = json["access_token"] as! String
(after receiving a successful JSON response)
You can then implement a Singleton as follows:
class Token {
// Can't init a singleton
private init() { }
static let sharedInstance = Token()
var tokenString = ""
}
If you want to save the token in a variable for using it later , try this
(key being the corresponding name of the key in your response object)
let token = httpResponse?.allHeaderFields["SECURITY-TOKEN"] as? String
let task = URLSession.shared.dataTask(with: request) { data, response, error in
let httpResponse = response as? HTTPURLResponse
let token = httpResponse?.allHeaderFields["SECURITY-TOKEN"] as? String
print(token)
}
task.resume()

JSON parsing in its own separate function is not working

All the tutorials that I have seen or read about Swift 3 JSON parsing include placing JSON parsing code inside viewDidLoad() func/method and it works great. I want to place JSON parsing code in its own function and call it from viewDidLoad(). Check below example:
class ViewController: UIViewController {
var ArrayImages = [String]();
override func viewDidLoad() {
super.viewDidLoad()
var json = ParseJson();
print("My Array = \(ArrayImages)");
}
// NEW FUNCTION
func ParseJson() {
let url = URL(string: "http://etasawoq.com/go_categories.php")!
URLSession.shared.dataTask(with: url) { (data, response, error) in
if (error != nil){
print("Error Found Creating URLSession : \(error)")
} else {
if let ParsedJson = data {
do {
let json = try JSONSerialization.jsonObject(with: ParsedJson, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
for x in json {
let row = x as! NSDictionary;
let imageUrl = row["image_url"] as! String
self.ArrayImages.append(imageUrl);
}
} catch {
print("Json Processing failed \(error)");
}
}
}
}.resume() // start session
}
}
Unfortunately, the "ArrayImages" is not being populated when calling the ParseJson function. The print output is "My Array = []". Why is that? How can I solve this problem while keeping JSON parsing code in a separate function?
Your response getting through block so you need to print array in side the block not outside as below .
do {
let json = try JSONSerialization.jsonObject(with: ParsedJson, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
for x in json {
let row = x as! NSDictionary;
let imageUrl = row["image_url"] as! String
self.ArrayImages.append(imageUrl);
}
print("My Array = \(ArrayImages)");
}

POST data while when getting JSON with SwiftyJSON

I'm developing an iOS app with Xcode and Swift.
I'm getting JSON data with SwiftyJSON.swift and the following code:
import UIKit
class ViewController: UIViewController {
var dict = NSDictionary()
#IBOutlet weak var firstLb: UILabel!
#IBOutlet weak var secondLb: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "http://example.com/showUserInfo.php"
if let url = NSURL(string: urlString) {
if let data = try? NSData(contentsOfURL: url, options: []) {
let json = JSON(data: data)
print(json)
let f = json[0]["name"].stringValue
let s = json[0]["age"].stringValue
firstLb.text = f
secondLb.text = s
}
}
}
}
That works fine but I want to be able to post to my PHP script. (My PHP script is ready for it. It can receive POST data and handle it.)
I normally use the following code to POST data to PHP:
let request = NSMutableURLRequest(URL: NSURL(string: "http://example.com/showUserInfo.php")!)
request.HTTPMethod = "POST"
let postString = "username=MyUserName"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
That means: I know how to get data with JSON and I know how to POST a value to PHP. But unfortunately I'm not able to combine both.
Does anybody know how to combine them? How to POST a value to a PHP script where getting the JSON data?
To post data to Server you should use In-build APIs, or you can use a very famous library called : Alamofire
Sample Code:
let params:[String:AnyObject] = [
"foo" : 1,
"bar" : 2
]
request(.POST, "URL", parameters: params)
.responseJSON { response in
switch response.result {
case .Success(let JSON):
print("JSON: \(JSON)")
case .Failure(let error):
print("Request failed with error: \(error)")
}
}

Swift JSON Parse execution on viewLoad

Im currently struggling with a small issue on my viewController. I have stored user information to hold the users logged in status, anyways when the user opens the app they are shown a "Profile" page. Im trying to (in this example return the email) return values related to that user as the app is opened but dont know how one would execute the code on the controller itself, my JSON is posted below and returns the correct needed information. However my Label will still not get the value of the users Email stored when they open the app. Label stays blank!
let myUrl = NSURL(string: "http://www.mywebsite.co.za/php/scripts/getuserEmail.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let postString = "user_id=\(userId)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
println(" response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("response data = \(responseString)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as? NSDictionary
if let parseJSON = json
{
var userEmail = parseJSON["userEmail"] as? String
self.usersEmail.text = userEmail
}
}
Would basically like the code to execute and update my label as that view opens, as the user has the ability to change the email from another viewController already so the email should update accordingly. Any other information will gladly be provided.
Added: println to console will not execute past the assigning of the myUrl variable. The reply below will still not work however this is my full code on viewWillAppear:
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
let userFirstName = NSUserDefaults.standardUserDefaults().stringForKey("userFirstName")
let userLastName = NSUserDefaults.standardUserDefaults().stringForKey("userLastName")
var userFullName = userFirstName!
userFullNameLabel.text = userFullName
let userId:String? = NSUserDefaults.standardUserDefaults().stringForKey("userId")
let imageUrl = NSURL(string:"http://www.mywebsite.co.za/profile-pictures/\(userId!)/user-profile.jpg")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let imageData = NSData(contentsOfURL: imageUrl!)
if(imageData != nil )
{
dispatch_async(dispatch_get_main_queue(),{
self.profilePictureImageVIew.image = UIImage(data: imageData!)
self.profilePictureImageVIew.backgroundColor = UIColor.clearColor()
})
}
}
// Send HTTP POST
let myUrl = NSURL(string: "http://www.mywebsite.co.za/php/scripts/getuserEmail.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let postString = "user_id=\(userId)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
// You can print out response object
println("******* response = \(response)")
// Print out reponse body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("****** response data = \(responseString)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as? NSDictionary
if let parseJSON = json
{
var userEmail = parseJSON["userEmail"] as? String
self.usersEmail.text = userEmail
}
}
}
If I understand correctly, you're saying the page appears and your call to the web has not finished and assigned to the self.usersEmail.text yet. What I did in my project was dispatch the commands in a block like yours asynchronously on the main queue. Try doing this inside your if statement:
dispatch_async(dispatch_get_main_queue()) {
var userEmail = parseJSON["userEmail"] as? String
self.usersEmail.text = userEmail
}
Hopefully this helps. It may be improper, but hopefully somebody can let me know if it is. It works for me so far.
You also need to resume the task after its block:
let myUrl = NSURL(string: "http://www.mywebsite.co.za/php/scripts/getuserEmail.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let postString = "user_id=\(userId)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
// You can print out response object
println("******* response = \(response)")
// Print out reponse body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("****** response data = \(responseString)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as? NSDictionary
if let parseJSON = json
{
var userEmail = parseJSON["userEmail"] as? String
self.usersEmail.text = userEmail
}
}
task.resume()
Thank you grdavis, marked as answer, I had however needed to change a few things to get the result I wanted and I just wanted to post the updated answer.
Moved to viewdidLoad and not viewWillAppear
When monitoring console the userID was not alone when being sent over the URL thus adding a '!' to the string fixed this too before sending the url
The resume worked
Below is my updated code, thank you again. Label updates like desired:
// Send HTTP POST
let userId:String? = NSUserDefaults.standardUserDefaults().stringForKey("userId")
let myUrl = NSURL(string: "http://www.mywebsite.co.za/php/scripts/getuserEmail.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let postString = "user_id=\(userId!)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)){
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
// You can print out response object
println("******* response = \(response)")
// Print out reponse body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("****** response data = \(responseString)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as? NSDictionary
if let parseJSON = json
{
var userEmail = parseJSON["userEmail"] as? String
println("******* userEmail = \(userEmail)")
self.usersEmail.text = userEmail
}
}
task.resume()
}

Create variables from JSON array

I'm trying hard to learn IOS development.
I have followed this guide and successfully managed to create a working quiz game. The last couple of days I have been trying to connect the game to an external database. Finally after many hours I'm able to read from MYSQL using JSON parsing.
Right now Im struggling with a way to convert the json array into a normal array.
My current hardcoded questions look like this:
let questionOne = questionTemplate("the first question?", answerOne: "a answer", answerTwo: "a second answer", answerThree: "a third aswer", answerFour: "tast possible answer", correctAnswer: 2)
Then they are added to an array
spormslaArray = [questionOne, questionTwo, questionThree, questionFour, questionFive, questionSix,questionSeven]
Then im doing some more loading of answers and questions before i add them to the GUI based on an array counter from the first to the last question.
func questionTemplate(question:String, answerOne:String, answerTwo:String, answerThree:String, answerFour:String, correctAnswer:Int) -> NSArray {
//Set the question
var quizQuestion = question
//set the answers and the right answer
var firstAnswer = answerOne
var secondAnswer = answerTwo
var thirdAnswer = answerThree
var fourthAnswer = answerFour
var rightAnswer = correctAnswer
var gjennverendeSporsmal = 1
//Add all the questions and answers to an array
let questionAnswerArray = [question, firstAnswer, secondAnswer, thirdAnswer, fourthAnswer, rightAnswer]
return questionAnswerArray
}
I now want to add questions from my database into spormslaArray.I got questions loaded into xcode using this code:
func lasteJson(){
let urlPath = "http://universellutvikling.no/utvikling/json.php"
let url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
if error != nil {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if err != nil {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
let json = JSON(jsonResult)
let count: Int? = json["data"].array?.count
// println("found \(count!) challenges")
//Im just setting a hardcoded number, it will be based on the array when I have figured that out
var tall = 7
let ct = count
for index in 0...tall-1 {
println(json["data"][index] )
//DEtte printer ut induviduelt
/*
if let questionId = json["data"][index]["id"].string {
println(questionId)
}
if let spm1 = json["data"][index]["answerOne"].string {
println(spm1)
}
if let spm2 = json["data"][index]["answerTwo"].string {
println(spm2)
}
if let spm3 = json["data"][index]["answerThree"].string {
println(spm3)
}
if let spm4 = json["data"][index]["answerFour"].string {
println(spm4)
}
if let correctAnswer = json["data"][index]["correctAnswer"].string {
println(correctAnswer)
}
*/
}
//}
})
task.resume()
This is mostly based on this code.
If Im ignoring the fact that Im getting some breakpoints when im running the app, and that nordic characters in my database makes the ios simulator crash; This is the parsing result in the command line:
{
"correctAnswer" : "1",
"id" : "0",
"answerThree" : "aa3",
"answerFour" : "aa4",
"questionTemplate" : "sporsmal",
"answerOne" : "as1",
"answerTwo" : "aa2"
}
//////Finally here is the problem///////
I have tried for hours to make a variable from the json array, into the guestion array.
I want to do something like this:
let questionOne = json["data"][index]["answerOne"].string
and then add them to an array
let questionArray[questionOne, QuestionTwo.. etc]
I have tried for hours without any progress, so my last hope is you guys! :-)
Use this...
To post JSON or to receive JSON (Leave dictionary nil to GET)
///Use completion handler to handle recieved data
func sendJSON(params:Dictionary<String, String>?, toAdressOnServer:String, customCompletionHandler:((parsedData:AnyObject?, statusCode: Int) -> Void)?){
var request = NSMutableURLRequest(URL: NSURL(string: SERVER_NAME + toAdressOnServer)!)
var session = NSURLSession.sharedSession()
var err: NSError?
if (params == nil){
request.HTTPMethod = "GET"
}else{
request.HTTPMethod = "POST"
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params!, options: nil, error: &err)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
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: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments , error: &err)
// 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)'")
customCompletionHandler?(parsedData: json, statusCode: -1)
}
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: AnyObject = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
// Use keyword "success" in JSON from server to register successful transmission
let success = parseJSON["success"] as? Int
if (success == nil){
customCompletionHandler?(parsedData: json, statusCode: -2)
}else{
customCompletionHandler?(parsedData: json, statusCode: success!)
}
}
else {
// 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)")
customCompletionHandler?(parsedData: json, statusCode: -1)
}
}
})
task.resume()
}
And To decode the JSON in your case the array, but it can have any form.
self.sendJSON(nil, toAdressOnServer: "ADRESS", customCompletionHandler: { (parsedData, statusCode) -> Void in
//check for valid data
if (parsedData != nil){
//Loop through results
for (var x = 0; x < parsedData!.count; x++){
///primary key of the item from the internet
let pk:Int = (parsedData![x] as NSDictionary).objectForKey("pk") as Int
let month = ((parsedData![x] as NSDictionary).objectForKey("fields") as NSDictionary).objectForKey("month")! as String
let quote = ((parsedData![x] as NSDictionary).objectForKey("fields") as NSDictionary).objectForKey("quote")! as String
let quotee = ((parsedData![x] as NSDictionary).objectForKey("fields") as NSDictionary).objectForKey("quotee")! as String
})
This is an example, use parsed data as "json" and use it with the appropriate structure. In this case the JSON was An array of some dictionary with a fields dictionary that has another dictionary with more fields. So you can have any JSON structure.
I Hope this helps!
It seems that you almost have the answer there. I think what you are missing is questionArray.append(... in your loop to build your array. You could also make things easier for yourself if you modified your JSON so that the questions were in an array rather than discrete keys and change your questionTemplate to take an array rather than discrete answers.
Working with what you have however -
func lasteJson(){
let urlPath = "http://universellutvikling.no/utvikling/json.php"
let url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
questionsArray=[Question]()
let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
if error != nil {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
else {
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if err != nil {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
else {
let questions=jsonResult["data"] as? [[String:String]]
if (questions != nil) {
for question in questions! {
let answer1=question["answerOne"]!
let answer2=question["answerTwo"]!
let answer3=question["answerThree"]!
let answer4=question["answerFour"]!
let id=question["id"]!
let questionTemplate=question["questionTemplate"]!
let correctAnswer=question["correctAnswer"]!
let newQuestion=Question(questionTemplate, answerOne: answer1, answerTwo:answer2, answerThree: answer3, answerFour: answer4, correctAnswer: correctAnswer)
questionsArray.append(newQuestion)
}
}
}
}
})
task.resume()
}
You don't show your questionTemplate, but I am not sure why/how it returns an array. My code above assumes that there is a class Question and fills in a property questionsArray

Resources