Reputation: 5651
I'm extremely new to handling JSON Data in Swift, and almost just as new to Swift. In a Playground I wrote a whole bunch of code that parsed JSON Data out.
However I realized I don't want to copy and paste this code into every view controller that uses only some of the data. I want to create a custom class that handles the json data.
Here is a bit of my code:
var status: String!
var message: String!
var code: Int!
var dataArray: [NSDictionary]!
var responseCode: String!
var url: NSURL!
var session: NSURLSession!
url = NSURL(string: "http://thisappgonnabecoool.json")
session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: { data, response, error -> Void in
if (error != nil) {
// println(error)
} else {
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
status = jsonResult["status"] as! String
message = jsonResult["message"] as! String
code = jsonResult["code"] as! Int
dataArray = jsonResult["data"] as! [NSDictionary]
}
})
task.resume()
I then attempted to create a class like this:
class JsonClass {
var status: String!
var message: String!
var code: Int!
var dataArray: [NSDictionary]!
var responseCode: String!
var url: NSURL!
var session: NSURLSession!
init() {
url = NSURL(string: "http://thisappgonnabecoool.json")
session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: { data, response, error -> Void in
if (error != nil) {
// println(error)
} else {
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
status = jsonResult["status"] as! String
message = jsonResult["message"] as! String
code = jsonResult["code"] as! Int
dataArray = jsonResult["data"] as! [NSDictionary]
}
})
task.resume()
}
I thought that within a new class I would be able to do something like this:
let jsonAPI = JsonClass()
println(jsonAPI.status)
println(jsonAPI.message)
etc...
However, any attempt to access an instance of the JsonClass results in every JsonClass property having a value of nil.
What are my next steps to accessing this data using instances of this class?
Upvotes: 3
Views: 1758
Reputation: 5651
Much thanks for everyone. I'm posting a sample of my API as the answer since it is the most complete answer.
As stated earlier, my issue wasn't with parsing, it had to do with the fact that dataTaskWithURL was called after the call to init() returns. I've solved the issue by adding a completion handler to the method I use to download the data.
class JsonAPI {
var status: String!
var message: String!
var code: Int!
var dataArray: [NSDictionary]!
var responseCode: String!
var url: NSURL!
var session: NSURLSession!
func getData(completionHandler: ((NSArray!, NSError!) -> Void)!) -> Void {
url = NSURL(string: "myapp.json")
session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: { data, response, error -> Void in
if (error != nil) {
// println(error)
//If there is an error, return nil for the data, and error for the error
return completionHandler(nil, error)
} else {
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
self.status = jsonResult["status"] as! String
self.message = jsonResult["message"] as! String
self.code = jsonResult["code"] as! Int
self.dataArray = jsonResult["data"] as! [NSDictionary]
}
//If there aren't errors, return whatever you parsed as the data, and nil for error
return completionHandler(self.dataArray, nil)
})
task.resume()
}
}
From separate classes I call the getData() method like this:
var api = JsonAPI()
api.getData({data, error -> Void in
if (data != nil) {
self.newDataArray = data
} else {
println("api.getData failed")
println(error)
}
})
Upvotes: 0
Reputation: 52592
Your problem has nothing at all to do with parsing JSON. Your problem is that you have an asynchronous call, and the asynchronous call isn't finished by the time you look at the results.
The completion handler of dataTaskWihURL can be called half a second, five seconds, or sixty seconds after the call to init () returns.
Upvotes: 4