func retrieveData(englishWord : String, completionHandler : (success: Bool, data : [String : AnyObject]?, errorString : String?) -> Void) {
let baseURL = "https://api.pearson.com/v2/dictionaries/ldoce5/entries?headword=vodka"
let urlString = baseURL
print(urlString)
let url = NSURL(string: urlString)
let request = NSMutableURLRequest(URL: url!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { data, response, error in
if error != nil {
completionHandler(success: false, data: nil, errorString: "There was a networking error")
return
}
if data == nil {
completionHandler(success: false, data: nil, errorString: "There was an error in the request for data")
return
}
let parsedResult : AnyObject?
do {
parsedResult = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! [String : AnyObject]
print(parsedResult!)
} catch {
completionHandler(success: false, data: nil, errorString: "There was an error in the conversion for data")
return
}
}
task.resume()
}
So right now print(parsedResult!) gives:
{
count = 1;
limit = 10;
offset = 0;
results = (
{
datasets = (
ldoce5,
dictionary
);
headword = vodka;
id = cqAG3cXCxZ;
"part_of_speech" = noun;
pronunciations = (
{
audio = (
{
lang = "British English";
type = pronunciation;
url = "/v2/dictionaries/assets/ldoce/gb_pron/vodka0205.mp3";
}
);
ipa = "\U02c8v\U0252dk\U0259";
},
{
audio = (
{
lang = "American English";
type = pronunciation;
url = "/v2/dictionaries/assets/ldoce/us_pron/vodka.mp3";
}
);
ipa = "\U02c8v\U0251\U02d0dk\U0259";
lang = "American English";
}
);
senses = (
{
definition = (
"a strong clear alcoholic drink originally from Russia, or a glass of this"
);
}
);
url = "/v2/dictionaries/entries/cqAG3cXCxZ";
}
);
status = 200;
total = 1;
url = "/v2/dictionaries/ldoce5/entries?headword=vodka";
}
But the query URL : Here
I posted it here for convenience:
{"status":200,"offset":0,"limit":10,"count":1,"total":1,"url":"/v2/dictionaries/ldoce5/entries?headword=vodka","results":[{"datasets":["ldoce5","dictionary"],"headword":"vodka","id":"cqAG3cXCxZ","part_of_speech":"noun","pronunciations":[{"audio":[{"lang":"British English","type":"pronunciation","url":"/v2/dictionaries/assets/ldoce/gb_pron/vodka0205.mp3"}],"ipa":"ˈvɒdkə"},{"audio":[{"lang":"American English","type":"pronunciation","url":"/v2/dictionaries/assets/ldoce/us_pron/vodka.mp3"}],"ipa":"ˈvɑːdkə","lang":"American English"}],"senses":[{"definition":["a strong clear alcoholic drink originally from Russia, or a glass of this"]}],"url":"/v2/dictionaries/entries/cqAG3cXCxZ"}]}
Is there a reason why NSJSONSerialization is changing my data as the data printed out is clearly different to what is returned by the Pearson API?
I don't believe it's actually changing the values, I believe you're just looking at a different representation. (If Swift behaves like Objective-C), the print(x) will call the "description" method on x, which can output the object in any format it likes to.
What you might want to do is reencode the data using: dataWithJSONObject:options:error (the essentially opposite call to what you made), and take a look at what the representation is.
https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSJSONSerialization_Class/#//apple_ref/occ/clm/NSJSONSerialization/dataWithJSONObject:options:error:
Related
I'm trying to parse the response object from an API call, but having some difficulty.
First, I parsed the returned JSON with following:
let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
if let result = responseObject["result"] {
print(result)
}
Then, when I log the result, following is what I get:
{
"_links" = {
next = "/api/3/action/datastore_search?limit=50&id=22f223e7-73f7-4842-935c-80a0ba5c3e5b&offset=50";
start = "/api/3/action/datastore_search?limit=50&id=22f223e7-73f7-4842-935c-80a0ba5c3e5b";
};
fields = (
{
id = "_id";
type = int;
},
{
id = package;
info = {
label = "";
notes = "Unique, normalized, name of dataset.
"type_override" = "";
};
type = text;
}
)
}
I tried parsing it again:
let finalResult = (try? JSONSerialization.jsonObject(with: result)) as? [String: Any]
But, I get the following error:
No exact matches in call to class method 'jsonObject'
Update
if let result = responseObject["result"] as? [String: Any] {
if let finalResult = result["records"] {
print(finalResult)
}
}
When I log this, I get the following:
(
{
"_id" = 186;
accessibility = 1;
completeness = "0.6899999999999999";
freshness = "0.5";
grade = Silver;
"grade_norm" = Silver;
metadata = "0.84";
package = "air-conditioned-and-cool-spaces-heat-relief-network";
"recorded_at" = "2019-12-17T20:24:09";
score = "0.78";
"score_norm" = "0.76";
usability = "0.86";
version = "v0.1.0";
},
{
"_id" = 187;
accessibility = 1;
completeness = 1;
freshness = 0;
grade = Bronze;
"grade_norm" = Bronze;
metadata = "0.25";
package = "air-conditioned-public-places-cooling-centres";
"recorded_at" = "2019-12-17T20:24:09";
score = "0.54";
"score_norm" = "0.31";
usability = "0.85";
version = "v0.1.0";
},
)
When I tried to iterate this:
for (key, value) in finalResult {
print("key", key)
print("value", value)
}
I get the following error:
Tuple pattern cannot match values of none-tuple type
Thanks to #OOPer, I was able to parse it as a dictionary:
if let result = responseObject["result"] as? [String: Any] {
if let finalResult = result["records"] as? [[String: Any]] {
finalResult.forEach { (catalogue) in
if let package = catalogue["package"] as? String {
}
}
}
}
I am using shopify iOS SDK(mobile-buy-sdk-ios) in react native to get login user's orders.
Here is my code,
let query = Storefront.buildQuery { $0
.customer(customerAccessToken: token) { $0
.orders(first: count, reverse: true) { $0
.edges { $0
.node { $0
.id()
.orderNumber()
.totalPrice()
.statusUrl()
.lineItems(first: 25){ $0
.edges{ $0
.node{ $0
.title()
.quantity()
.variant{ $0
.id()
.price()
.title()
.image{ $0
.originalSrc()
}
}
}
}
}
let task = self.client.queryGraphWith(query, cachePolicy: .networkOnly) { response, error in
error.debugUserPrint()
let userOrders = response.customer?.orders.edges[0].node;
let res = try! JSONSerialization.data(withJSONObject: userOrders)
completion([res])
}
And I am getting this response in userOrders variable
<QueryRoot: ["customer": {
orders = {
edges = (
{
node = {
id = "Z2lkOi8vc2hvcGlmeS9PcmRlci8yMjY2NTM3NzU0NzEwP2tleT0zNWFiYzBkMjRmMDk3MjZlYzgzYjkwZDVlZGI5YjM4MA==";
lineItems = {
edges = (
{
node = {
quantity = 1;
title = "Gift wrapping";
variant = {
id = "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMjE3MzkzNjYyMzcwMg==";
image = {
originalSrc = "https://cdn.shopify.com/s/files/1/2331/3377/products/Gift_Boxes_11_22_2017_Standard_1024x1024_60d01a1c-f665-4c9e-b80b-f6fda9167de3.jpg?v=1521444032";
};
price = "10.00";
title = "Default Title";
};
};
}
);
};
orderNumber = 1040;
statusUrl = "23313377/orders/11f378e7df2731521429f377015d2ec2/authenticate?key=35abc0d24f09726ec83b90d5edb9b380";
totalPrice = "10.00";
};
}
);
};
}]>)
this formate, so try to parse this data to JSON object to pass data from iOS function to javascript function. I have tried
JSONSerialization.data(withJSONObject: userOrders)
but it is not working. I just want to parse this data to JSON. I have also tried many other ways but no luck.
Thanks.
They're a number of ways I can think of...
Alamofire if you have access to that query endpoint
Alamofire.request("http://feeds.news24.com/articles/Fin24/Tech/rss").responseJSON { json in
/// do what you want with your json
}
No endpoint, use SwiftyJSON
let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string {
//Now you got your value
}
I don't think there is straightforward way to get JSON, using mobile-buy-sdk. However you can convert response to JSON
if let data = try? JSONSerialization.data(withJSONObject: userOrders.fields, options: .prettyPrinted) {
print(String(data: data, encoding: .utf8))
}
There are many many examples of retrieving the value of a key, and I can do that. In this case, the key has multiple values. The key is "mining", followed by 6 values. The same key:value is repeated 30 times, with different values for the keys of course.
What I can't seem to solve is how to return the values. Especially the first one, 1532825277682891390, for example, which appears to be a sub-key with key/value pairs related to that.
The todo is: ["mining": {
1532825277682891390 = {
command = mining;
siteid = "Platform Mining";
ts = 1532825270557;
user1 = 73276;
value = 1;
};
1532826406100318457 = {
command = mining;
siteid = "Platform Mining";
ts = 1532826375712;
user1 = 73276;
value = 1;
};
1532827074955562013 = {
command = mining;
siteid = "Platform Mining";
ts = 1532827066645;
user1 = 73276;
value = 1;
};
153282775791322835 = {
command = mining;
siteid = "Platform Mining";
ts = 1532827753205;
user1 = 73276;
value = 1;
};
....
....
....
}
I can show the key:value for the "mining" key. There are only two keys in the dictionary, 'mining' and 'success' - I'm not worried about 'success', it usually returns '1'.
This is basically the code with a few examples and trial outputs, as I try out different things from other posts. I just can't get my head around this bit.
Do I need to put the dictionary into an array, and how do I do that, or can I just put each value into a var, so I can print them to a UITabDisplay?
func makeGetCall() {
// Set up the URL request
let todoEndpoint: String = "https://api.jsecoin.com/v1.7/mining/auth/"
let apiKey = "xxxxxxxxxxxxxxxxxxxxxxx"
guard let url = URL(string: todoEndpoint) else {
print("Error: cannot create URL")
return
}
var urlRequest = URLRequest(url: url)
urlRequest.setValue(apiKey, forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
// set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// make the request
let task = session.dataTask(with: urlRequest) {
(data, response, error) in
// check for any errors
guard error == nil else {
print("error calling GET on /todos/1")
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
print("Got data: \(responseData)")
// parse the result as JSON, since that's what the API provides
do {
guard let todo = try JSONSerialization.jsonObject(with: responseData, options: [])
as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
// now we have the todo
// let's just print it to prove we can access it
print("The todo is: " + todo.description)
// from this point on I"m experimenting ....
let dict = todo.description
print("The dict is: " + dict)
let keys = Array(todo.keys)
// prints ["mining", "success"]
print(keys)
/////////////////////////////////
if let alb = todo["mining"] {
// prints all the values for 'mining'.
// {
// 1532825277682891390 = {
// command = mining;
// siteid = "Platform Mining";
// ts = 1532825270557;
// user1 = 73276;
// value = 1;
// };
// ........ 30 entires
print(alb)
}
//======================
let index1 = todo.index(forKey: "mining")
let myMining = (todo[index1!].value)
// again prints all the mining values. Mining: {
// 1532825277682891390 = {
// command = mining;
// siteid = "Platform Mining";
// ts = 1532825270557;
// user1 = 73276;
// value = 1;
// };
print("Mining: \(myMining)")
//============
You can do it in a similar way you have written for taking the keys of todo dictionary.
if let mining = todo["mining"] as? [String: Any] {
let miningKeys = Array(mining.keys)
// It will be like [1532825277682891390, 1532826406100318457]
}
Use the miningKeys for accessing the values from that mining dictionary, like:
mining[miningKeys.first!]
// It will return
// {
// command = mining;
// siteid = "Platform Mining";
// ts = 1532825270557;
// user1 = 73276;
// value = 1;
// }
The value for key mining is a dictionary. Conditional downcast alb to the expected type and enumerate the dictionary
if let alb = todo["mining"] as? [String:Any] {
for (key, value) in alb {
print(key, value)
}
}
If you want to print each key-value pair of the inner dictionary separately you could use
if let alb = todo["mining"] as? [String:Any] {
for (key, mining) in alb {
print(key)
if let item = mining as? [String:Any] {
for (key, value) in item {
print(key, value)
}
}
}
}
Consider that the keys in the for loop are not guaranteed to be in the same order as in the JSON.
I have been trying to get the below code to return an array of information that can use in a UIPickerView class "title for Rows. The code does not work, I do now that when I run the print script it does return a list of all the values from my JSON values. A sample of parsed JSON. I have been watching YouTube Videos and reading info about this for two evenings now. Any help would be great. Everything I find sends Parsed JSON results to a table view.
{
date = "2017-05-01";
"financial_institution" = "Your Neighbourhood C.U.";
"five_year" = "2.79";
"four_year" = "3.15";
key = 86;
"one_year" = "2.79";
"six_months" = 0;
"three_year" = "3.09";
"two_year" = "2.89";
"variable_rate" = 0;
}
)
func getJSONData()
{
let url = URL(string:"")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("error")
}
else {
if let mydata = data {
do {
let myJson = try JSONSerialization.jsonObject(with: mydata, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(myJson)
var lenderName = myJson["financial_institution"]
for i in lenderName {
var lender = "financial_institution"
lender += "\(i)"
var lenderList = myJson[lender].string as String!
lenderNamesArray.append(lenderList)
}
}
catch {
// catch error
}
}
}
}
task.resume()
}
I'm using facebook-api to fetch user's friends. The code is as follows:
let params = ["fields": "id"]
let request = FBSDKGraphRequest(graphPath: "me/friends", parameters: params)
request.startWithCompletionHandler { (connection : FBSDKGraphRequestConnection!, result : AnyObject!, error : NSError!) -> Void in
if error != nil {
let errorMessage = error.localizedDescription
print(errorMessage)
/* Handle error */
}
else if result.isKindOfClass(NSDictionary){
/* handle response */
let defaults = NSUserDefaults.standardUserDefaults()
let resultdict = result as! NSDictionary
let data : NSArray = resultdict.objectForKey("data") as! NSArray
for i in 0..<data.count {
let valueDict : NSDictionary = data[i] as! NSDictionary
let id = valueDict.objectForKey("id") as! String
print("the id value is \(id)")
}
let friends = resultdict.objectForKey("data") as! NSArray
print("Found \(friends.count) friends")
print(friends)
defaults.setObject(friends, forKey: "fb_friends")
defaults.synchronize()
}
}
The resultDict contains:
{
data = (
{
id = 1662200084096651;
}
);
paging = {
cursors = {
after = QVFIUmFsa0JGazI4amNEcFczT0NRQzdiNshusdsDSHFDHFDDSm02UzNudV9ZATS1ESk5iUEQ5T2syNGDSw4yegdxbdf4WGZA3;
before = QVFIUmFsa0JGazI4amNEcFczT0NRQzdiNURGQTgdsgdsHFDSHTRTNU9DSm02UzNudV9ZATS1ESk5iUEQ5T2syNkRjQW8xc1drGgdsGREHRTcXE4WGZA3;
};
};
summary = {
"total_count" = 762;
};
}
The print above prints (for 1 fb friend):
(
{
id = 1020XXXXXX305XXX;
}
)
I want to pass this to my server, so I thought about doing:
var emptyParams = ["":""]
emptyParams["friends"] = (defaults.objectForKey("fb_friends") as! NSArray).componentsJoinedByString(",")
but then instead of params:
friends: 1020XXXXXX305XXX
I have:
"friends": {
id = 10206503694305180;
}
I want to skip the id and send it as an array, because on my server I have:
var friends = req.body.friends;
for(var i=0; i<friends.length; i++) {
console.log(friends[i]);
query = query.or([{ 'fb_friend': friends[i] }]);
}
how should my modify my swift code so that it creates a correct request?
From what I understand of your code, fb_friends have type of [[String:String]] and you want convert it to [String]?
You can use .map to get "id" from the dictionary.
let friends = (defaults.objectForKey("fb_friends") as! NSArray)
.map{$0["id"]!}
.joinWithSeparator(",")
let params = [
"friends": friends
]