JSON Serialization with accent - ios

I am facing a trouble when I try getting a remote JSON file with accents. If I take off the accents of the JSON file, it works perfectly, but if I keep them, I have an error. As you are able to verify, I have tried to use "NSUTF8StringEncoding", however, it did not work as well. Any Idea?
func getJSON(completionHandler: ((NSArray!, NSError!) -> Void)!) -> Void
{
var urlAux = "http://www.xxxx.com/downloads/example.json"
var urlAuxUTF8 = urlAux.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let url: NSURL = NSURL(string: urlAuxUTF8!)
let ses = NSURLSession.sharedSession()
var enc:NSStringEncoding = NSUTF8StringEncoding
var error: NSError?
let content = NSString.stringWithContentsOfURL(url, usedEncoding:&enc, error:&error)
if (error != nil)
{
NSLog("error: %#", error!)
exit(-1)
}
else
{
let json = NSJSONSerialization.JSONObjectWithData(content.dataUsingEncoding(enc)!, options:nil, error: &error) as NSDictionary
if (error != nil) {
return completionHandler(nil, error)
} else {
return completionHandler(json["express"] as [NSDictionary], nil)
}
}
}

You have perfectly fine NSData, you convert it to a string and have to guess the encoding, then you convert it to NSData again. Use a function that gets the NSData directly, without any conversion to a string, and pass it to NSJSONSerialization as it is.

Related

Error while casting value to string with Swift IOS8

I'm new to programming for ios so my question may be silly ;-) I'm trying to parse some JSON data. My code look's like:
var task = session.dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if(error != nil){
println("error")
}else{
var error: NSError?
var wetherData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSMutableDictionary
var wd = wetherData["current_observation"] as NSMutableDictionary
var xd = wd["temp_c"]! as String
println(xd);
}
})
I want xd variable to be a string but while casting i have an error
println(wd["temp_c"]) returns "Optional(4)"
wd["temp_c"] look's like this

Swift - Expected expression in list of expressions

I'm new to Swift been reading but have no clue what this means. On the line of code below, I have "Expected expression in list of expressions" after parameters[String]. AS well at the same point it is looking for "Expected ',' separator. I believe these are related.
AppDelegate.submitLacunaRequest(module: "empire", method: "login", parameters[String]:["myuserid", "mypassword", "mykey"]) {
responseObject, error in
// some network error or programming error
if error != nil {
println("error = \(error)")
println("responseObject = \(responseObject)")
return
}
// network request ok, now see if login was successful
if let responseDictionary = responseObject as? NSDictionary {
if let errorDictionary = responseDictionary["error"] as? NSDictionary {
println("error logging in (bad userid/password?): \(errorDictionary)")
} else if let resultDictionary = responseDictionary["result"] as? NSDictionary {
println("successfully logged in, refer to resultDictionary for details: \(resultDictionary)")
} else {
println("we should never get here")
println("responseObject = \(responseObject)")
}
}
}
Here is the related code from AppDelegate
public func submitLacunaRequest (#module: String, method: String, parameters: AnyObject, completion: (responseObject: AnyObject!, error: NSError!) -> (Void)) -> NSURLSessionTask? {
let session = NSURLSession.sharedSession()
let url = NSURL(string: "https://us1.lacunaexpanse.com")?.URLByAppendingPathComponent(module)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("application/json-rpc", forHTTPHeaderField: "Content-Type")
let requestDictionary = [
"jsonrpc" : "2.0",
"id" : 1,
"method" : "login",
"params" : ["myuserid", "mypassword", "mykey"]
]
var error: NSError?
let requestBody = NSJSONSerialization.dataWithJSONObject(requestDictionary, options: nil, error: &error)
if requestBody == nil {
completion(responseObject: nil, error: error)
return nil
}
request.HTTPBody = requestBody
let task = session.dataTaskWithRequest(request) {
data, response, error in
// handle fundamental network errors (e.g. no connectivity)
if error != nil {
completion(responseObject: data, error: error)
return
}
// parse the JSON response
var parseError: NSError?
let responseObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parseError) as? NSDictionary
if responseObject == nil {
// because it's not JSON, let's convert it to a string when we report completion (likely HTML or text)
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding) as String
completion(responseObject: responseString, error: parseError)
return
}
completion(responseObject: responseObject, error: nil)
}
task.resume()
return task
}
You are using external parameter name for a parameter when calling the function, but the external parameter is not defined in your function declaration. Simply use it this way.
submitLacunaRequest(module: "empire", "login", ["myuserid", "mypassword", "mykey"]) {
You're calling the function incorrectly. You don't need the [String] in the parameters param...
AppDelegate.submitLacunaRequest(module: "empire", method: "login", parameters: ["myuserid", "mypassword", "mykey"]) {
...
}
I called my function parameter protocol.
If I was to try using this property as usual, I would notice it to be written in pink being a keyword and I would rename it.
Instead, I used this property in a string like this and I didn't get any clues from the compiler:
func configure(_ protocol: Protocol, host:String, port:String) {
urlString = "\(protocol)://\(host):\(port)"
}
I spend good 5 minutes confused out of my mind by this error, but then I figured it out. The problem was in the name of the parameter.
I didn't want to rename the parameter, so I ended up writing it like this:
urlString = "\(`protocol`)://\(host):\(port)"

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

How can I remove this JSON wrapper in swift?

I'm currently making an app in swift that essentially functions as a virtual stock trading game. I was able to get most of the data I need using Yahoo's YQL service. A particular feature that I am working on now is a search function so that users can search for a stock ticker. I am making the app for IOS using Swift. The problem is I call JSON using this url:
http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=f&callback=YAHOO.Finance.SymbolSuggest.ssCallback
Which includes the extra text "YAHOO.Finance.SymbolSuggest.ssCallback(" and ")" around the JSON data which causes the code to be unable to parse the JSON data. How can I remove this? Thank you in advance.
Here is my code:
let callURL = NSURL(string: "http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=f&callback=YAHOO.Finance.SymbolSuggest.ssCallback")
var errorEncountered: Bool = false
var downloadFinished: Bool = false
var arrayOfStockResults: [[String]] = []
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask =
sharedSession.downloadTaskWithURL(callURL!, completionHandler: {
(location: NSURL!, response: NSURLResponse!, error: NSError!)
-> Void in
if (error != nil) {
errorEncountered = true
}
if (errorEncountered == false) {
let dataObject = NSData(contentsOfURL: location)
let stocksDictionary =
NSJSONSerialization.JSONObjectWithData(dataObject!, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
println(stocksDictionary)
if (error != nil) {
errorEncountered = true
}
downloadFinished = true
I don't know why you're using downloadTaskWithURL and then using NSData's dataWithContentsOfURL to get the data. It's simpler to use dataTaskWithURL. The following code worked for me to download the data, convert it to a string, trim that string to remove unwanted text, convert that string back to an NSData object, and finally to get the dictionary.
var sharedSession: NSURLSession!
override func viewDidLoad() {
super.viewDidLoad()
let callURL = NSURL(string: "http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=f&callback=YAHOO.Finance.SymbolSuggest.ssCallback")
var arrayOfStockResults: [[String]] = []
sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDataTask = sharedSession.dataTaskWithURL(callURL!, completionHandler: { (data, response, error) -> Void in
if error != nil {
println(error)
}else{
var jsonError: NSError?
var text: NSString = NSString(data: data, encoding: 4)!
var range = text.rangeOfString("ssCallback")
var subtext: NSString = text.substringFromIndex(range.location + range.length)
var finalText = subtext.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "()")) // trim off the parentheses at both ends
var trimmedData = finalText.dataUsingEncoding(4, allowLossyConversion: false)
if let stocksDictionary = NSJSONSerialization.JSONObjectWithData(trimmedData!, options: .AllowFragments, error: &jsonError) as? NSDictionary {
println(stocksDictionary)
}else{
println(jsonError)
}
}
})
downloadTask.resume()
}
You could substring the request body
let startIndex = //enough to cut out yahoo prepend
let endIndex = //enough to cut off that ending paren
//assuming some data variable for request body
data.substringWithRange(Range<String.Index>(start: startIndex, end: endIndex))
then json-ify it!

Cannot load JSON from php/mysql in Swift

I'm trying to build an IOS App for my php/mysql website. The problem is I can't get the following code working with my created JSON output. But the same code works with other APIs like :
http://www.telize.com/geoip
Here is my code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Playground - noun: a place where people can play
let urlPath = "https://www.example.com/API_OUT.php?API_KEY=785d...e5f5"
let url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
println("Task completed")
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)")
} else {
println(jsonResult)
}
})
task.resume()
}
}
This JSON is an array, not a dictionary (unlike your original JSON, which was a dictionary). Thus your assignment of this new JSON to a dictionary will fail.
I would suggest (a) use NSArray rather than NSDictionary; and (b) use if let ... syntax rather than just let, to gracefully handle these errors in the future.
Thus, that yields:
var parseError: NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parseError) as? NSArray {
println(jsonResult)
} else {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(parseError?.localizedDescription)")
}

Resources