Trying to use SwiftyJSON library, but struggling for a day or so now.
I got this JSON.
“blah”:[{“xdeltaY":0,"xdeltaX":0,"blah1":435,"blah2":"\/Numbers\/Numbers.001.png","height":693.2142857142857,"width":1200,"blah3":240}]
I read it in from a file and assign it like this?
let quickfix = String(data: response.1, encoding: String.Encoding.utf8)
let json2F = JSON(quickfix!)
It seems to work. I can print this.
json2F.debugDescription
But I can do next to nothing beyond that. It hasn't parsed seems, I think it is just a string.
I am unable to figure out how to access the data within it. I also tried this...
if let dataFromString = quickfix?.data(using: .utf8, allowLossyConversion: false) {
let json2E = JSON(data: dataFromString)
print("json2E debugDescription \(json2F.debugDescription)")
}
But it returns null!! How to use this library?
You code looks good to me. It seems that your JSON is not valid.
Try to put an encapsulating object {} around it. Like this:
{"blah": [{"xdeltaY":0, "xdeltaX":0, "blah1":435, "blah2":"\/Numbers\/Numbers.001.png", "height":693.2142857142857, "width":1200, "blah3":240}]}
And additionally make sure you are using the right "not ”.
String+JSON
I also like to share a extension I use for getting my JSON from a string, which also gives you error messages in the console logs to prevent invalid JSON to mess up your program.
import Foundation
import SwiftyJSON
public extension String {
public func toJSON() -> JSON? {
if let data = self.data(using: String.Encoding.utf8, allowLossyConversion: false) {
var jsonError: NSError?
let json = JSON(data: data, error: &jsonError)
if jsonError == nil {
return json
} else {
print(jsonError!.description)
}
}
return nil
}
public func toJSONValue() -> JSON {
return self.toJSON() ?? JSON.null
}
}
Related
As a Swift newcomer, I am very confused about how to parse some JSON data obtained from an API. I am able to get the JSON data from the api using an alamofire request. At this point, I think I have an NSDictionary object, JSON as print(JSON) logs to console a good deal of JSON.
if let result = response.result.value {
let JSON = result as! NSDictionary
print("this is what JSON is")
print(JSON)
My question is, first, is JSON in fact an NSDictionary. Second, how would I access a value in the JSON. Do I need to first convert this to a data object. Or how do I get at the nested data.
For example, let's say the JSON looks like this:
{
"contact": {
"first": "Bob",
"second":"Jones"
}
}
I came across this code on SO:
let data = JSON(data: JSON)
print("data\(data["contact"]["first"])")
But it throws an error. I have swiftyJSON installed but happy for solution with or without it.
Thanks in advance for any suggestions
Can you try
if let result = response.result.value as? [String:Any] {
if let contact = result["contact"] as? [String:Any] {
if let first = contact["first"] as? String {
print(first)
}
}
}
also this
let data = JSON(data: JSON)
gives error because parameter should be of type Data not Dictionary
I would prefer to return Data from Alamofire request and use Decodable to parse it and convert to required model
TRY THIS!
if let data = response.data {
let jsonData = JSON(data: data)
print("data : \(jsonData["contact"]["first"].string)")
}
Swift4 introduce amazing Codable protocol.
Using Codable, we can model JSONObject or PropertyList file into equivalent Struct or Classes by writing very few lines of code.
There are many online tool available which creates model class from you JSON
(http://www.json4swift.com/)
Example
let decoder = JSONDecoder()
let parsedObject = try decoder.decode(Class.self, from: data)
You can find detail at below link:
https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
I'm trying to integrate a login API in my iOS project. When i hit that API in browser it gives me correct JSON response. Whereas, when i call it in my app, i'm unable to read JSON. Code is as:
let url = NSURL(string: "myURL")
let request = NSURLRequest(URL: url!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error != nil {
print (error)
}
do {
//jsonDict is always nil
if let jsonDict = try self.jsonFromData(data!) {
print (jsonDict)
}
}
catch {
print ("hi")
}
}
jsonFromData is as:
private func jsonFromData(jsonData: NSData) throws -> [NSDictionary]?
{
var jsonDict: [NSDictionary]? = nil
do
{
jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) as? [NSDictionary]
}
catch
{
throw(error)
}
return jsonDict
}
Response of API, when hit in browser is as:
Please help me, what i am doing wrong. Thanks.
UPDATE:
I just checked that if i convert data to String, it gives correct value. i.e.
let string = NSString(data: jsonData, encoding: NSASCIIStringEncoding)
print (string)
//OUTPUT: Optional({"Authenticated":true,"CustomerID":000,"CustomerName":"TEMP","Members":[{"MemberID":000,"MemberNumber":"000","MembershipID":00,"MembershipExpiration":"\/Date(1517464799000-0600)\/","ValidBuyerTypes":[0]}]})
Look at your code where you decode the JSON and the as? statement. You are trying to get an array of NSDictionary. Your JSON as printed contains a single dictionary, not an array.
This looks right to me. The only thing I can think is that (despite what the string output looks like) the top level container of your response is NOT an NSDictionary. In your jsonFromData function, instead of assuming the result of JSONObjecWithData will be an NSDictionary, I would say:
let iDunnoWhatThisIs = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) // don't cast this to NSDictionary
and see what you get back. It should either be a dictionary or an array, however, since you have NSJSONReadingOptions.AllowFragments set for the options, it's possible that it could be something else entirely. Start with making SURE you're actually getting back what you're assuming you are and go from there.
Try using NSKeyedUnarchiver instead:
jsonDict = NSKeyedUnarchiver.unarchiveObjectWithData(jsonData)! as NSDictionary
I'm a beginner so please be gentle.
Ok so I successfully parse my JSON from the server and can access all of its contents but know I'm kind of stuck here:
//Functionn for fetching API data
func fetchRates(){
//Set EndPoint URL
let url = URL(string: endPoint)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error as Any)
}
do {
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
let dictonary = json as? [String: Any?]
let ratesJson = dictonary?["rates"] as? [String: Double]
print(ratesJson as Any)
} catch let jsonError {
print(jsonError)
}
}.resume()
}
Now I want to get my ratesJson Dictionary out of this function and actually use its contents to do some calculations, but after hours of trying and searching I still have no idea how.
I just want to:
Get JSON data stored presistently (for offline use)
Update the Data when the app launches and overwrite the old data
The possibilities I've come across so far are CoreData, which seems really confusing and complicated and Realm which I don't really know at all.
Help would be very much appreciated and sorry if this seems really stupid
Since you have the JSON parsing, I would create a object class to store the data using Core Data. There is a lot that goes into core data usage at first, but it is well worth the time investment to learn if you plan on continuing iOS development. Core Data Tuts
I also do not know what you plan on doing with your app, or the purpose, and Core Data might be a little overkill according to your purpose, but you could always save the updated JSON each time, overwriting a file in the device's document's dir, then read the data back in and parse it again.
You can write the JSON data to a outputstream using:
JSONSerialization.writeJSONObject(_ obj: Any, to stream: OutputStream, options opt: JSONSerialization.WritingOptions = [], error: NSErrorPointer)
//Write JSON data into a stream. The stream should be opened and configured.
//The return value is the number of bytes written to the stream, or 0 on error.
//All other behavior of this method is the same as the dataWithJSONObject:options:error: method.
UPDATE: Ok I think I see your question now. There are two ways that you can go about getting your data back to your view controller: 1. Delegate pattern 2.Closures. I personally like using delegates over closures.
With delegates you will need to create a protocol:
protocol SessionDataTaskComplete {
func dataDownloaded(parsedJson : [String : Double])
}
And inside of your URLSession class you will need a class variable to hold that protocol delegate:
var dataTaskCompleteDelegate : SessionDataTaskComplete?
Then you will need to have your view controller implement that protocol:
class MyViewController: UIViewController, SessionDataTaskComplete {
override func viewDidLoad() {
super.viewDidLoad()
//Also assign your viewController as your URLSession's SessionDataTaskComplete delegate
myURLSession.dataTaskCompleteDelegate = self
}
func dataDownloaded(parsedJson : [String : Double]) {
//Handle data as you wish here
}
}
Now in your fetchRates() you can use that delegate to pass the data back to your viewController:
func fetchRates(){
//Set EndPoint URL
let url = URL(string: endPoint)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error as Any)
}
do {
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
let dictonary = json as? [String: Any?]
let ratesJson = dictonary?["rates"] as? [String: Double]
//print(ratesJson as Any)
if (dataTaskCompleteDelegate != nil) {
dataTaskCompleteDelegate!.dataDownloaded(parsedJson: ratesJson)
}
} catch let jsonError {
print(jsonError)
}
}.resume()
}
If you are not comfortable with using the delegate pattern, that is something else I would suggest spending time learning, as it is used all over with the iOS SDK. Try to think of them as an object assigning a duty/task to another object.
I have added to my project the SwiftyJSON.swift file and I am trying to get some data from the web. Now my project runs but only until the line where I am trying to get the array from json in a dictionary. I cannot understand where the problem is, but I am guessing it has to be something very stupid as I am just in the beginning with learning swift.
I am just trying to print in the console the name of all the movies from that url and after I manage to achieve this performance, I will try to get the summary of the movie as well and then put them in a TableView.
import UIKit
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//grab the status code and check if the transfer was successful == 200
let requestURL: NSURL = NSURL(string: "https://itunes.apple.com/us/rss/topmovies/limit=50/json")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
//sort through the stations key and cast the data into an array of dictionaries
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
print("bbbbb")
// From here on, it doesn't print anything anymore
if let movies = json["entry"] as? [[String: AnyObject]] {
print(movies)
print("test")
for movie in movies {
if let name = movie["name"] as? String {
print("mmmm")
print("%# (Built %#)",name)
}
}
}
}catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
entry is an json array, Use .array
if let movies = json["entry"].array {
for movie in movies {
// Do stuff
}
}
Also a general tip. Do not cast the values e.g.
movie["something"] as? String
Rather use the built in features:
movie["something"].string
Update
Looking closer on your code I see that you are acctually not using SwiftyJSON.swift at all.
To use Swifty you parse the json text like this and get a JSON object:
let jsonObj = JSON(data: yourData) // data is a NSData
Please have another look at the documentation:
https://github.com/SwiftyJSON/SwiftyJSON
I think you are reading the section "Why is the typical JSON handling in Swift NOT good?". That section explains the native and "bad" way of managing json in Swift, the real documentation is further down.
Ok, so I'm using alamofire and the parameters I'm passing are valid. Here is the code so far:
Alamofire.request(.POST, "http://mywebservice.com", parameters: myparameters)
.response { (request, response, data, error) in
if(error != nil){
print("error= \(error)")
}else{
print("there was no error so far ")
print(data)
var json = JSON(data!)
print(json) //prints unknown
print(json["id"]) //prints null
}
}
}
I tried different things but so far nothing worked. I'm using alamofire and swiftyjson, the response json that comes from webservice is:
{
"id": "432532gdsg",
"username": "gsdgsdg"
}
and I want to print both values separately in case of success. How can I do it?
Your issue comes from this line:
var json = JSON(data!)
The JSON() initializer from SwiftyJSON can take several type of inputs.
When you don't specify the type in the init, SwiftyJSON tries to infer the type itself.
Unfortunately it sometimes fails silently because it will have misinterpreted the input.
So, when using SwiftyJSON with NSData, the solution is to specify the "data:" parameter for the JSON initializer:
var json = JSON(data: data!)
Try this
Alamofire.request(.POST, "http://mywebservice.com", parameters : myparameters , encoding : .JSON )
.responseData{ response in
let json = JSON(data.response.result.value!)
print(json)
let id=json["id"]
let username=json["username"]
print(id)
print(username)
}