Parsing JSON Swift - ios

I am working on an app that displays the live Bitcoin price. I am using 2 APIs to do this - one plaintext, and one JSON. I am having a bit of trouble with the JSON API.
Here's a bit of my Swift code
func BTCFallback(){
var string2 = currencySelector.currentTitle
var url = NSURL(string:"https://bitpay.com/api/rates/" + (string2)!)
var request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:fallback)
var data = NSData(contentsOfURL:url);
let value = NSString(string: USD.text).doubleValue / NSString(data:data, encoding:NSUTF8StringEncoding).doubleValue
// Define JSON string
var JSONString = "\(data)"
// Get NSData using string
if let JSONData = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
// Parse JSONData into JSON object
var parsingError: NSError?
if let JSONObject = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &parsingError) as? [String: AnyObject] {
// If the parsing was successful grab the rate object
var rateObject: AnyObject? = JSONObject["rate"]
// Make sure the rate object is the expected type
if let rate = rateObject as? Float {
println("rate is \(rate)")
BTC.text = "\(rate)"
}
} else {
// There was an error parsing the JSON data
println("Error parsing JSON: \(parsingError)")
BTC.text = "err1"
}
}
}
In the above code, currencySelector.currentTitle is equal to an ISO currency code, for instance USD. BTC.text is a UI element.
The expected behavior is that the code will set the counterpart of "rate" as the text of BTC.text. In case this helps, the API returns something like {"code":"USD","name":"US Dollar","rate":376.71}. I would want, using the above example, to have BTC.text set to 376.71
Here's what's happening: the consoe gives the error
Error parsing JSON: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x16eb0f60 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})
What am I doing wrong? Thanks in advance!

It is all a matter of handling the returned data and de-serialization.
Here is example code, note that the handling of Optionals should be better, this is just to demonstrate the basic code. For example purposes I used a simple synchronous web call.:
var url: NSURL! = NSURL(string:"https://bitpay.com/api/rates/AUD")
var request = NSURLRequest(URL: url)
var response: NSURLResponse?
var error: NSError?
var data: NSData? = NSURLConnection.sendSynchronousRequest(request, returningResponse:&response, error:&error)
println("data: \(data)")
if let data: NSData = NSURLConnection.sendSynchronousRequest(request, returningResponse:&response, error:&error) {
println("data: \(data)")
var parsingError: NSError?
if let rateDictionary = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parsingError) as NSDictionary? {
println("rateDictionary: \(rateDictionary)")
// If the parsing was successful grab the rate object
if var rateString: AnyObject = rateDictionary["rate"] {
println("rateString: \(rateString)")
// Make sure the rate object is the expected type
if let rate = rateString.floatValue {
println("rate is \(rate)")
}
}
}
}
Ouput:
data: Optional(7b22636f 6465223a 22415544 222c226e 616d6522 3a224175 73747261 6c69616e 20446f6c 6c617222 2c227261 7465223a 3430372e 39393137 7d)
rateDictionary: {
code = AUD;
name = "Australian Dollar";
rate = "407.9917";
}
rateString: 407.9917
rate is 407.992

Related

HTTP Get receive JSonObjects Swift DebugDescription=Invalid value around character 0

I'm getting an issue while sending an HTTP GET command to a server to retrieve JSONObjects.
here is the command:
if let url: NSURL = NSURL(string: "http://11.22.33.44:8080/SRV/getAllUsers?owner=\(User.sharedInstance.email)") {
print("\nSending URL: \(url)")
let request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{
(response: NSURLResponse?, data: NSData?, error: NSError?)-> Void in
print("Response: \(response) \n")
do{
var datastring = NSString(data:data!, encoding:NSUTF8StringEncoding) as String?
print("Data: \(datastring)")
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
print("Json: \(json)")
}catch {
print("Error with Json: \(error)")
}
});
I received a HTTP 200 with all header information, but I'm trying to print NSData as String (nil) and also trying to retrieve my JSONObjects, I get the following message:
Data: nil
Error with Json: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
I'm managing the server part, the servlet which is preparing JSONObjects is doing the following:
ObjectOutputStream objOut = new ObjectOutputStream(response.getOutputStream());
JSONObject jsonObj = new JSONObject();
jsonObj.put("id","1234");
objOut.writeObject(jsonObj);
objout.flush();
jsonObj = new JSONObject();
jsonObj.put("id","5678");
objOut.writeObject(jsonObj);
objout.flush();
and a last important information, I'm able to retrieve those JSONObject from an Android application without any problem but it seems the format expected in swift for JSONObjects are not the same...
EDIT
I changed the way to send HTTP GET command by using NSURLSession but before treating the JSONObject, I'm trying at least to display data as String:
typealias Payload = [String: AnyObject]
let url = NSURL(string: "http://11.22.33.44:8080/SRV/getAllUsers?owner=\(User.sharedInstance.email)")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in
if(error == nil)
{
let err : NSError! = nil
print("Response \(response)")
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Data: \(dataString)")
var json: Payload!
// 1
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as? Payload
print("JSon: \(json)")
} catch {
print(error)
//XCPlaygroundPage.currentPage.finishExecution()
}
}
else
{
print(error?.description)
}
}
task.resume()
I Received a HTTP 200 with the right header information, so I'm sure the servlet is successfully called, but get nil in data
Data: nil
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
EDIT #2
by using the following line
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error data")
return
}
print("data: \(data?.debugDescription)")
I can retrieve the following:
data: Optional("OS_dispatch_data: data[0x7fc68bc45380] = { composite, size = >1067, num_records = 5 record[0] = { from = 0, length = 404, data_object = >0x7fc68bc999d0 }, record[1] = { from = 0, length = 135, data_object = >0x7fc68be1f830 }, record[2] = { from = 0, length = 264, data_object = >0x7fc68bc99a80 }, record[3] = { from = 0, length = 133, data_object = >0x7fc68bf97c20 }, record[4] = { from = 0, length = 131, data_object = >0x7fc68bca0b40 }, }>")
means I am able to retrieve data (at least!) but I don't know how I can extract from this data my JSONObject....
SOLUTION
I finally found my problem.
server part needs to prepare JSONObject like this:
response.setContentType("application/json");
// Get the printwriter object from response to write the required json object to the output stream
PrintWriter out = response.getWriter();
// Assuming your json object is **jsonObject**, perform the following, it will return your json object
out.print(jsonObject);
out.flush();
instead of using ObjectOutPutStream.
Swift part can retrieve it like this:
let url_to_request = "http://11.22.33.44:8080/SRV/getAllUsers?owner=\(User.sharedInstance.email)"
let url:NSURL = NSURL(string: url_to_request)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
request.timeoutInterval = 10
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error data")
return
}
var json: AnyObject?
do
{
json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
for anItem in json as! [Dictionary<String, AnyObject>] {
let nom = anItem["nom"] as! String
let prenom = anItem["prenom"] as! String
let id = anItem["id"] as! String
print("nom: \(nom) prenom: \(prenom) id: \(id)")
}
}
catch
{
print("error Serialization")
return
}
}
task.resume()

Trouble unwrapping JSON Array to a String Value

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)
}
}

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

Establish Error Case in NSURLConnection, JSON Parsing in Swift

I am attempting to pull information from a JSON on my website. In doing so, if there is an error with the connection, it should return that error and log it to the console. The problem I am running into is that if I turn on Airplane more or otherwise lose signal, the error: fatal error: unexpectedly found nil while unwrapping an Optional value crashes the application. Why is it returning this, when I have set conditions for the error to simply be logged? Thank you in advance!
I am unsure why the error is not being logged and preventing the application from crashing. Any pointers would be helpful.
JSONLoader.swift
import Foundation
var arrayOfMeals: [Meal] = [Meal]()
var weekDayArray = ["monday"]
func getJSON(urlToRequest: String) -> NSDictionary {
var url: NSURL = NSURL(string: urlToRequest)!
var jsonRequest: NSURLRequest = NSURLRequest(URL: url)
var jsonResponse: AutoreleasingUnsafeMutablePointer<NSURLResponse?> = nil
var error: NSError?
var dataValue: NSData = NSURLConnection.sendSynchronousRequest(jsonRequest, returningResponse: jsonResponse, error:&error)!
if error? == nil {
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataValue, options: NSJSONReadingOptions.MutableContainers , error: &error) as NSDictionary
NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
if error? == nil {
return jsonResult
}
else {
return NSDictionary(object: "Error: Something with parsing went wrong :(", forKey: "error")
}
}
else {
return NSDictionary(object: "Error: There was an error with your connection :(", forKey: "error")
}
}
func loadJSON(jsonDictionary: NSDictionary) {
for days in weekDayArray{
var resultsArray = jsonDictionary[days] as NSArray
for obj: AnyObject in resultsArray{
let breakfast = (obj.objectForKey("breakfast")! as String)
let lunch = (obj.objectForKey("lunch")! as String)
let dinner = obj.objectForKey("dinner")! as String
let dateString = obj.objectForKey("dateString")! as String
let dayOfWeek = obj.objectForKey("dayOfWeek")! as String
let newMeal = Meal(breakfast: breakfast, lunch: lunch, dinner: dinner, dayOfWeek: dayOfWeek, dateString: dateString)
if theDays(newMeal.dateString) >= 0 {
arrayOfMeals.append(newMeal)
}
}
}
}
I expect the function getJSON to establish an NSURLConnection to the site, parse the JSON date, and return an NSDictionary. An error case is established if there is an error in the connection, then it returns the dictionary with a value explaining the error. An additional error case occurs to parse the JSON file, and returns an NSDictionary with similar error.
I expect the function loadJSON to create instances of an object Meal, which I define as having properties of breakfast, lunch, dinner, a date, and a day of the week. The values of this instance are the results of the returned NSDictionary from function getJSON. If the day is the future, append it to my arrayOfMeals. Otherwise, ignore the instance.
MealViewController
override func viewDidLoad() {
super.viewDidLoad()
var req = getJSON("http://www.seandeaton.com/meals/Mealx")
loadJSON(req)
}
MealModel.swift - to create instances of the meals
class Meal {
let breakfast: String
let lunch: String
let dinner: String
let dayOfWeek: String
let dateString: String
init(breakfast: String, lunch: String, dinner: String, dayOfWeek: String, dateString: String) {
self.breakfast = breakfast
self.lunch = lunch
self.dinner = dinner
self.dayOfWeek = dayOfWeek
self.dateString = dateString
}
}
How can I prevent the app from crashing upon failure to establish a connection and log the error message to the console? Thanks again.
The key observation is that in the call to sendSynchronousRequest in which you're retrieving the NSData, you have defined NSData to not be optional, and you appended a ! which will force the unwrapping of the optional return value. Thus if the optional NSData was nil (which would happen if there were any network problems), this code would fail.
Instead, you should simply leave the NSData as an optional (i.e. a NSData?) and check whether it was nil or not before trying to unwrap it. Thus, I might suggest something like:
func retrieveJSON(urlToRequest: String) -> NSDictionary {
let url: NSURL = NSURL(string: urlToRequest)!
let jsonRequest: NSURLRequest = NSURLRequest(URL: url)
var jsonResponse: NSURLResponse?
var error: NSError?
let dataValue = NSURLConnection.sendSynchronousRequest(jsonRequest, returningResponse: &jsonResponse, error:&error)
if dataValue != nil {
if let jsonResult = NSJSONSerialization.JSONObjectWithData(dataValue!, options: .MutableContainers, error: &error) as? NSDictionary {
return jsonResult
} else {
return [
"error": "Error: Something with parsing went wrong :(",
"localizedDescription": error?.localizedDescription ?? ""
];
}
}
else {
return [
"error": "Error: There was an error with your connection :(",
"localizedDescription": error?.localizedDescription ?? ""
];
}
}
The above will fix crashes resulting from the forced unwrapping of the optional NSData, which would have been be nil if there were networking problems. Note, you don't show us the code that calls getJSON and then subsequently calls loadJSON, but I assume you're doing the necessary checking for error handling there.
Note, I also retired the awkward AutoreleasingUnsafeMutablePointer<NSURLResponse?> construct. I also added the localizedDescription of the error to the dictionary being returned.
Personally, I'd generally return the complete NSError object and the NSURLResponse objects, so that the caller can diagnose the precise nature of the error, rather than just text descriptions.
In a more radical edit to your code, I'd suggest you generally avoid synchronous requests. Never perform synchronous requests from the main thread.
For example, you might define the method to perform the request asynchronously, like so:
func retrieveJSON(urlToRequest: String, completionHandler:(responseObject: NSDictionary?, error: NSError?) -> ()) {
let url: NSURL = NSURL(string: urlToRequest)!
let jsonRequest: NSURLRequest = NSURLRequest(URL: url)
var jsonResponse: NSURLResponse?
NSURLConnection.sendAsynchronousRequest(jsonRequest, queue: NSOperationQueue.mainQueue()) {
response, data, error in
if data == nil {
completionHandler(responseObject: nil, error: error)
} else {
var parseError: NSError?
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &parseError) as NSDictionary?
completionHandler(responseObject: jsonResult, error: error)
}
}
}
You'd then call it, using the "trailing closure syntax", like so:
retrieveJSON(urlString) {
responseObject, error in
if responseObject == nil {
// handle error here, e.g.
println(error)
return
}
// handle successful the `NSDictionary` object, `responseObject`, here
}
// but don't try to use the object here, because the above runs asynchronously

Parse Google Calendar JSON in SWIFT

I'm brand new to Swift development. I'm trying to build a basic app which will read a feed from Google Calendar which is returned in JSON.
I am able to use a NSURLConnection.sendAsynchronousRequest call as described in this thread: Make REST API call in Swift and I get a result of some sorts.
My problem is I am unable to parse the JSON into some meaningful objects from which I can create a list of upcoming events.
My code this far is:
var url : String = "some url"
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil){
// No idea how to parse this object as it seems to be a NSDictionary but battling to interact with it.
}
else
{
}
})
Any help would be greatly appreciated.
If you put a breakpoint after
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
then you'll be able to see the dictionary key/value pairs. I copied/pasted your code and see this:
You can access the values by using jsonResult.objectForKey("keyName"). I'm also going to downcast using as DataType.
Example)
let encoding = jsonResult.objectForKey("encoding") as String
let version = jsonResult.objectForKey("version") as String
let feed = jsonResult.objectForKey("feed") as NSDictionary

Resources