Load JSON result in swift - json

I am trying to parse JSON result obtained from Playframewordk 1.2 into swift.
Playframework result:
public JsonObject getJson() {
JsonObject jsonObject = new JsonObject();
if (codeJson != null) {
for (String field : codeArticleFields) {
if (codeJson.has(field)) {
jsonObject.add(field, codeJson.get(field));
}
}
}
return jsonObject;
}
view playframework
#{extends 'main.html' /}
#{set title:'Test' /}
#{set 'moreScripts' }
#{/set}
${product?.getJson()}
Here is the code of swift:
func connectProductDatabase() {
let urlString = "http://api.autoidlabs.ch/test/" + "4025089060857"
let url: NSURL = NSURL(string: urlString)!
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = url
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler: {
(response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: NSError?
if let result = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error)
as? NSArray {
let dataArray = result[0] as NSArray
println(dataArray)
} else {
let resultString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Flawed JSON String: \(resultString)")
}
})
println("not connected")
}
As a result I am getting the entire file with all HTML tag. This is because it is not entering into the if statement. (I also tried with options:NSJSONReadingOptions.MutableContainers)
I tried with lot of result found from stackoverflow, but getting the same problem. If I understand well, the playframework view is not really returning a JSON, JsonObject of java is a formatted String as JSON.
How can I solve this problem?

I was able to solve the problem.
Instead of NSArray I used NSDictionary
if let result = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error)
as? NSDictionary {
and then in playframework I used renderJSON instead of render.

Related

Finishing the completion handler that fetches JSON from web, SWIFT [duplicate]

I am currently trying to download, parse and print JSON from an URL.
So far I got to this point:
1) A class (JSONImport.swift), which handles my import:
var data = NSMutableData();
let url = NSURL(string:"http://headers.jsontest.com");
var session = NSURLSession.sharedSession();
var jsonError:NSError?;
var response : NSURLResponse?;
func startConnection(){
let task:NSURLSessionDataTask = session.dataTaskWithURL(url!, completionHandler:apiHandler)
task.resume();
self.apiHandler(data,response: response,error: jsonError);
}
func apiHandler(data:NSData?, response:NSURLResponse?, error:NSError?)
{
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
catch{
print("API error: \(error)");
}
}
My problem is, that the data in
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
remains empty.
When I debug,the connection starts successfully, with the given url as a parameter. But my jsonData variable doesn't get printed. Instead the catch block throws the error, stating that there is no data in my variable:
API error: Error Domain=NSCocoaErrorDomain Code=3840 "No value."
Can someone please help me with this?
What am I missing?
Thank you all very much in advance!
[Edited after switching from NSURL Connection to NSURLSession]
Here's an example on how to use NSURLSession with a very convenient "completion handler".
This function contains the network call and has the "completion handler" (a callback for when the data will be available):
func getDataFrom(urlString: String, completion: (data: NSData)->()) {
if let url = NSURL(string: urlString) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (data, response, error) in
// print(response)
if let data = data {
completion(data: data)
} else {
print(error?.localizedDescription)
}
}
task.resume()
} else {
// URL is invalid
}
}
You can use it like this, inside a new function, with a "trailing closure":
func apiManager() {
getDataFrom("http://headers.jsontest.com") { (data) in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let jsonDict = json as? NSDictionary {
print(jsonDict)
} else {
// JSON data wasn't a dictionary
}
}
catch let error as NSError {
print("API error: \(error.debugDescription)")
}
}
}

HTML code in Swift String (not NSString)

I am downloading HTML source code of a webpage this way:
let url = NSURL(string: "http://www.example.com")
var error: NSError?
let html = NSString(contentsOfURL: url!, encoding: NSUTF8StringEncoding, error: &error)
if (error != nil) {
println("whoops, something went wrong")
} else {
println(html!)
}
But I would like to get it as String instead of NSString. Is there any way?
Swift's String also accepts the same initializer:
let html = String(contentsOfURL: url!, encoding: NSUTF8StringEncoding, error: &error)
I would suggest to use safe unwrapping with if let for your values:
var error: NSError?
if let url = NSURL(string: "http://www.example.com"), let html = String(contentsOfURL: url, encoding: NSUTF8StringEncoding, error: &error) {
if error != nil {
println(error)
} else {
println(html)
}
}
Last note: no need to use brackets around the condition in Swift.
Update for Swift 2 (Xcode 7)
if let url = NSURL(string: "http://www.example.com"),
let html = try? String(contentsOfURL: url, encoding: NSUTF8StringEncoding) {
print(html)
}

swift json type data parsing after get data

I'm developing a function which is receiving some JSON after calling a NSURLRequest in Swift. I am having issues accessing the different data values with subscript after I have parsed the result.
The following is the retrieved JSON:
{"retCode":100,"retMsg":"Success","retData":{"usn":92,"id":"clipsys#gmail.com","nickname":"ppigimi","profile_image":"..\/upload\/profile\/20150528172839.jpeg","language":"jp","join_channel_nm":"korfolk","cert_key":"696D6FB453DC141E5295E9D8E37B8DD0F1AFC8E34CE30B74551ED74A447AC564","cert_flag":"Y","join_date":"20150518155650","token":"3ea0a5fec1b55a5a23b5f1dc5c14b040dcd71eea"}}
The following is my code. I don't know how to get the values usn and token inside of retData.
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
// You can print out response object
println("response = \(response)")
// 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? NSDictionary
if let parseJSON = myJSON as? [String: AnyObject] {
// Now we can access value of First Name by its key
var retCode = parseJSON["retCode"] as? Int
println("retCode: \(retCode)")
if let retData = parseJSON["retData"] as? [AnyObject] {
for data in retData {
/**let usn = data["usn"]
println("USN = \(usn)")**/
}
}
if retCode == 100 {
//NSUserDefaults.standardUserDefaults().setValue("usn", forKey: String)
}
dispatch_async(dispatch_get_main_queue(), {
var myAlert = UIAlertController(title: "Alert", message: "AAAAAA", preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title: "OK", style:UIAlertActionStyle.Default) {
action in
self.dismissViewControllerAnimated(true, completion: nil);
}
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated: true, completion: nil);
});
}
}
task.resume()
The problem is that you are accessing retCode as [AnyObject]. It is not an Array, but actually a JSON object. You will need to cast it to a Dictionay, for example [String : AnyObject].
This means that your for loop where you are accessing the data can look something like the following:
if let retData = parseJSON["retData"] as? [String : AnyObject] {
for data in retData {
println("data is: \(data)")
/**let usn = data["usn"]
println("USN = \(usn)")**/
}
}

Swifty Json getting unknown but long way works fine?

I'm attempting to use SwiftyJson to pull some JSON data.
What's unusual is the "println(json)" says "unknowon" while if I pull the JSON data the regular way it works just fine -- the "println(pop)" says medium, as expected.
Below is the code I'm using. I started cutting out parts until I got to "println(json)" and then decided to try and handle it manually to see if it's SwiftyJson or me.
Any suggestions? I'm fairly new to iOS programming so I'm assuming I'm being silly in some form or another.
var ghostlandsJsonUrl: NSURL = NSURL(string: "http://us.battle.net/api/wow/realm/status?realm=Ghostlands")!
var jsonData: NSData!
var request: NSURLRequest = NSURLRequest(URL: ghostlandsJsonUrl)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
jsonData = data
if(jsonData != nil) {
let json = JSON(jsonData)
println(json)
} else {
println("jsonData: nil value... net down again?")
}
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let statuses = jsonObject as? NSDictionary{
if let realms = statuses["realms"] as? NSArray{
if let realm = realms[0] as? NSDictionary{
if let pop = realm["population"] as? NSString{
println(pop)
}
}
}
}
});
task.resume()
Looking at SwiftyJSON source code I can see that JSON is a simple struct. It implements the Printable protocol. Which give support to the print methods.
public var description: String {
if let string = self.rawString(options:.PrettyPrinted) {
return string
} else {
return "unknown"
}
}
Which means that for a reason or another the rawString method returns nil.
public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
switch self.type {
case .Array, .Dictionary:
if let data = self.rawData(options: opt) {
return NSString(data: data, encoding: encoding)
} else {
return nil
}
case .String:
return (self.object as String)
case .Number:
return (self.object as NSNumber).stringValue
case .Bool:
return (self.object as Bool).description
case .Null:
return "null"
default:
return nil
}
}
As you are fairly new to iOS development, I will tell you that the constructor doesn't expect a NSData object.
Here is the source:
public var object: AnyObject {
get {
return _object
}
set {
_object = newValue
switch newValue {
case let number as NSNumber:
if number.isBool {
_type = .Bool
} else {
_type = .Number
}
case let string as NSString:
_type = .String
case let null as NSNull:
_type = .Null
case let array as [AnyObject]:
_type = .Array
case let dictionary as [String : AnyObject]:
_type = .Dictionary
default:
_type = .Unknown
_object = NSNull()
_error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
}
}
}
So you should pass it the unserialized NSData as it:
if let jsonData = data {
//jsonData can't be nil with this kind of if
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
let json = JSON(jsonObject)
println(json)
//...
The constructor of JSON does the serialisation. Below is the constructor code from SwiftyJSON git repo where you can directly pass the NSData.
public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
do {
let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error.memory = aError
}
self.init(NSNull())
}
}
In simple, you can directly use the data returned in the completion handler of NSURLSession data task as below in your code.
let json = JSON(data: jsonData)

Converting JSON to NSData, and NSData to JSON in Swift

I'm having problems converting a JSON element into NSData, and an NSData variable back into JSON in Swift.
Firstly, I'd like to extract the encryptedData element of the following JSON data:
{
"transactionID" : 12345,
"encryptedData" : [-67,51,-38,61,-72,102,48]
}
into an NSData encryptedData variable but can't seem to be able to do it. I'm using SwiftyJSON to parse the JSON as follows:
let list: Array<JSON> = json["encryptedData"].arrayValue!
But this gives me an array of ScalarNumber which I don't know how to store into an NSData object.
Secondly, I'd like to generate JSON back from the same NSData object:
let jsonObject = [
"transactionID" : 12345,
"encryptedData" : encryptedData
]
But the NSData encryptedData object doesn't get converted into [-67,51,-38,61,-72,102,48], it just seems to nullify the JSON string.
Any ideas?
Here is code to convert between JSON and NSData in swift 2.0 (adapted from Shuo's answer)
// Convert from NSData to json object
func nsdataToJSON(data: NSData) -> AnyObject? {
do {
return try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers)
} catch let myJSONError {
print(myJSONError)
}
return nil
}
// Convert from JSON to nsdata
func jsonToNSData(json: AnyObject) -> NSData?{
do {
return try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted)
} catch let myJSONError {
print(myJSONError)
}
return nil;
}
In SwiftyJSON you can use rawData method to get NSData:
if let encryptedData:NSData = json["encryptedData"].rawData() {
NSLog(NSString(data: encryptedData, encoding: NSUTF8StringEncoding)!)
}
To generate JSON as you want you should convert data to array object:
if let encryptedDataArray = JSON(data: encryptedData).arrayObject {
let jsonObject:JSON = [
"transactionID" : 12345,
"encryptedData" : encryptedDataArray
]
NSLog(NSString(data: jsonObject.rawData()!, encoding: NSUTF8StringEncoding)!)
}
I have no idea on SwiftyJSON. I use following code snippet to convert between json and nsdata
// Convert from NSData to json object
public class func nsdataToJSON(data: NSData) -> AnyObject? {
return NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil)
}
// Convert from JSON to nsdata
public class func jsonToNSData(json: AnyObject) -> NSData?{
return NSJSONSerialization.dataWithJSONObject(json, options: .allZeros, error: nil)
}
#Sunil Targe here is the Swift3 version. Hope this helps. (Adapted from Ciprian Rarau's answer)
Convert data to JSON
func dataToJSON(data: Data) -> Any? {
do {
return try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
} catch let myJSONError {
print(myJSONError)
}
return nil
}
Convert from JSON to data
func jsonToData(json: Any) -> Data? {
do {
return try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted)
} catch let myJSONError {
print(myJSONError)
}
return nil;
}
Swift 4 that works for me:
// Convert from JSON to nsdata
func jsonToNSData(json: AnyObject) -> NSData?{
do {
return try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted) as NSData
} catch let myJSONError {
print(myJSONError)
}
return nil;
}
class ViewController: UIViewController {
let requestURL : NSURL = NSURL(string: "http://www.learnswiftonline.com/Samples/subway.json")!
let session = URLSession.shared
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData()
{
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(url: requestURL as URL)
let task = session.dataTask(with: urlRequest as URLRequest) { (data, response, error) -> Void in
let httpResponse = response as! HTTPURLResponse
let statusCode = httpResponse.statusCode
if(statusCode == 200)
{
do {
let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
print(jsonResponse as! NSDictionary)
}
catch let error
{
print(error)
}
}
}
task.resume()
}
}
Swift 5 with SwiftyJSON that works for me:
import SwiftyJSON
func getDataFrom(JSON json: JSON) -> Data? {
do {
return try json.rawData(options: .prettyPrinted)
} catch _ {
return nil
}
}
func getJSONFrom(Data data: Data) -> JSON? {
do {
return try JSON(data: data, options: .mutableContainers)
} catch _ {
return nil
}
}