Get data from complex JSON in swift - json

I have a complex JSON data.
How can I parse this data?
I've tried, but it does not work.
I need a Dictionary with object (id, time...). But how to get through "1,.."?
And how can I take time begin and end?
"data": {
"1":[
{"id":6524612,
...
"time":{
"begin":"18:50",
"end":"19:20"
},
...
},
"2":[
{
"id":6524613,
...
"time":{
"begin":"18:50",
"end":"19:20"
},
...
},
Where is my mistake?
let broadcastTask = broadcastSession.dataTaskWithRequest(broadcastRequest) { (data, response, error) -> Void in
if error != nil {
print(error.debugDescription)
} else {
do {
let broadcastDict = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? Dictionary<String, AnyObject>
if let results = broadcastDict!["data"] as? [Dictionary<String, AnyObject>] {
for obj in results {
let broadcast = Broadcast(broadcastDict: obj)
self.broadcastList.append(broadcast)
}
//Main UI thread
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadData()
}
}
} catch {
}
}
}
broadcastTask.resume()
init(broadcastDict: Dictionary<String, AnyObject>) {
if let category = broadcastDict["id"] as? Int {
self.id = id
}
...
}

If I understand the question correctly:
The first problem seems to be that you are trying to cast the "data" dictionary to an array of dictionaries. This will always fail because your data object is a dictionary and not an array.
Once you correct that problem you will run into trouble with your loop. Try this:
for (key, value) in results {
let broadcast = Broadcast(broadcastDict: value)
self.broadcastList.append(broadcast)
}
Now you are sending the dictionary that your Broadcast object is expecting.

Related

Value of type 'Type' has no subscripts Error Swift

Trying to sort the array of JSON objects in the array by "name" alphabetically. Gives error of "Value of type 'IndividualContact' has no subscripts" Not sure what that means. Any help is appreciated.
class Contacts{
var contact = [IndividualContact]()
init?(data2: Data) {
do {
if let json2 = try JSONSerialization.jsonObject(with: data2) as? [String: Any], let body = json2["data2"] as? [String: Any] {
if let contacts = body["contacts"] as? [[String: Any]] {
self.contact = ( contacts.map { IndividualContact(json2: $0) } )
}
}
contact.sorted(by: { ($0["name"] as! String) < ($1["name"] as! String) })
} catch {
print("Error deserializing JSON: \(error)")
return nil
}
}
}
The compiler is telling you that your object (IndividualContact) doesn't provide an implementation for the subscript token, i.e. [...]. While you could provide that implementation in your struct/class, doing so might be overkill in this situation. You probably just want to call $0.name in your sorted(by:) closure:
contact.sorted(by: { $0.name < $1.name })
If you really do want to use the $0["name"] syntax, then you can provide such an implementation. It might look something like this:
subscript(key: String) -> String {
get {
switch key {
case "name":
return self.name
default:
return ""
}
}
set {
...
}
}
More info on subscripts can be found here: https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html

reduce function is printing an empty dictionary [:]

I have reduced my dictionary keys successfully in this question as pseudo-code without a real json model. The goal which I accomplished in the previous question is to return only the keys that have matching values. So the output is a dictionary that looks something like this ["WoW": ["#jade", "#kalel"]. Exactly what I needed. Of course there could be other matches and I'd like to return those as well.
Now that I have a proper json model, the reduce function is printing out an empty dictionary [:]. Is it the type in .reduce(into: [String:[String]]() that is causing the issue?
All the data is printing so the json and model structure must be correct.
json
[
{
"id": "tokenID-tqkif48",
"name": "#jade",
"game": "WoW",
"age": "18"
},
{
"id": "tokenID-fvkif21",
"name": "#kalel",
"game": "WoW",
"age": "20"
}
]
UserModel
public typealias Users = [UserModel]
public struct UserModel: Codable {
public let name: String
public let game: String
// etc...
enum CodingKeys: String, CodingKey {
case name
case game
// etc...
Playground
guard let url = Bundle.main.url(forResource: "Users", withExtension: "json") else {
fatalError()
}
guard let data = try? Data(contentsOf: url) else {
fatalError()
}
let decoder = JSONDecoder()
do {
let response = try decoder.decode([UserModel].self, from: data)
for userModel in response {
let userDict: [String:String] = [ userModel.name:userModel.game ]
let reduction = Dictionary(grouping: userDict.keys) { userDict[$0] ?? "" }.reduce(into: [String:[String]](), { (result, element) in
if element.value.count > 1 {
result[element.key] = element.value
}
})
// error catch etc
}
Your code is too complicated. You can group the array by game simply with
let response = try decoder.decode([UserModel].self, from: data)
let reduction = Dictionary(grouping: response, by: {$0.game}).mapValues{ usermodel in usermodel.map{ $0.name}}
UPDATE I may be mistaking what you want to get. There's another code below and please check the results and choose one you want.
If you want to use reduce(into:updateAccumulatingResult:), you can write something like this.
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(name: String, game: String)] = response.map {($0.name, $0.game)}
let reduction = userArray.reduce(into: [String:[String]]()) {result, element in
if !element.game.isEmpty {
result[element.name, default: []].append(element.game)
}
}
print(reduction)
} catch {
print(error)
}
If you prefer an initializer of Dictionary, this may work:
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(name: String, games: [String])] = response.map {
($0.name, $0.game.isEmpty ? [] : [$0.game])
}
let reduction = Dictionary(userArray) {old, new in old + new}
print(reduction)
} catch {
print(error)
}
Both output:
["#jade": ["WoW"], "#kalel": ["WoW"]]
Anyway, your way of combining loop, Dictionary(grouping:) and reduce(into:) in addition of userDict.keys is making things too complex than they should be.
ADDITION When you want to get a Dictionary with keys as games:
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(game: String, name: String)] = response.compactMap {
$0.game.isEmpty ? nil : ($0.game, $0.name)
}
let reduction = userArray.reduce(into: [String:[String]]()) {result, element in
result[element.game, default: []].append(element.name)
}
print(reduction)
} catch {
print(error)
}
Or:
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(game: String, names: [String])] = response.compactMap {
$0.game.isEmpty ? nil : ($0.game, [$0.name])
}
let reduction = Dictionary(userArray) {old, new in old + new}
print(reduction)
} catch {
print(error)
}
Output:
["WoW": ["#jade", "#kalel"]]

Read from API JSON using Alamofire Swift 4

i have hard time to read JSON using Alamofire. below is the structure of the API response
{
"data": [
{
"order": {
"id": 258,
"created_at": "2018-07-01T14:51:05+08:00",
"user_id": "1234"
},
"transactions": [
{
"transaction_type": "rent",
"cabinet_id": "02110A0000C6",
"jack_id": 1
}
]
}
]
}
Basically, i need to print out only the array of transactions and also print one by one the transaction_type, cabinet_id, and jack_id
The previous one i just manage to print the api response using code below
Alamofire.request(WalletRouter.urlUserActiveOrder(id: userId)).responseJSON { response in
if let value = response.result.value {
let dict = value as? Dictionary<String, AnyObject>
//print (value)
if let innerDict = dict!["data"] {
print (innerDict) //manage to return the value
let data = innerDict["transactions"] as! NSArray //get error here
print (data)
}
}
//do your json stuff
else if (response.result.isFailure) {
//Manager your error
switch (response.error!._code){
case NSURLErrorTimedOut:
//Manager your time out error
break
case NSURLErrorNotConnectedToInternet:
//Manager your not connected to internet error
break
default:
print ("error")
}
}
}
i have already spent 6 hour to solve this, but still failed to get the value.
Create a struct class like below
struct Result: Decodable {
struct data12: Decodable {
struct transaction: Decodable {
let transactionType:String
let cabinetId:String
let jackId:Int
}
let transactions:[transaction]
}
let data:[data12]
}
Data fetching like this
do {
let data1 = try Data(contentsOf: URL(fileURLWithPath: path), options: [])
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let courses = try decoder.decode(Result.self, from: data1)
print(courses)
} catch {
print(error)
}
if anyOne think my approach is wrong please update my answer TIA

Looping through JSON object in Swift

I got this JSON object which I sent from my server to my Swift application.
{
"625289": {
"id": 1,
"subject": "Hello World"
},
"625277": {
"id": 2,
"subject":"Bye World!"
}
}
So i tried to get the subject for each result ("625289" and "625277") by doing as below in my Swift class:
struct Resultat : Decodable {
let subject: String
}
var result = [Resultat]()
let urlll = URL(string:"http://localhost:8888/api/pouet.php")
URLSession.shared.dataTask(with: urlll!) { (data, response, error) in
do {
print("coucoulol")
//print(response)
self.result = try JSONDecoder().decode([Resultat].self, from: data!)
print(self.result)
for eachTicket in self.result {
print(eachTicket.subject)
}
} catch {
print("error"+error.localizedDescription)
}
}.resume()
However, when I tried to execute the code, it says "The data couldn’t be read because it isn’t in the correct format." From what I understand, the loop for in the code is suffice to get the values in the arrays or maybe I'm wrong. Any help is appreciated, thanks.
The root object is a dictionary. You can decode the object to [String:Resultat]. The dictionary contains also dictionaries. An array is not involved.
struct Resultat : Decodable {
let subject: String
let id : Int
}
...
let result = try JSONDecoder().decode([String:Resultat].self, from: data!)
for (key, value) in result {
print(key, value.subject)
}
You can try using SwiftyJSON below
$0.0 = Key
$0.1 = value
let data = JSON(result)
data.dictionaryValue.forEach({
print($0.1)
})

Object At Index of Array with Value For Key

Does anyone know how to get the object at the index of an array, at the value for a specific key, and set it to a string?
I used to do this in Objective-C, but I can't quite figure out how to do it in Swift:
NSString *rT = [[self.rA objectAtIndex:0] valueForKey:#"Value"];
I've tried different things like this, but they don't work:
if let JSON = response.result.value {
print("JSON: \(JSON)")
var name: String? = self.rA[0].valueForKey("item_1") as? String
}
Endpoint:
[
{
"item_1": "Austin",
"item_2": "Texas"
}
]
Logging:
2016-04-01 13:35:42.787 A[66185:7391524] Response Array: (
{
"item_1" = Austin;
"item_2" = Texas;
}
)
I assume that you have something like array of dictionaries, So I made some test here it is sample code :
UPDATE
let jsonString = "[ { \"item_1\": \"Austin\", \"item_2\": \"Texas\" }, { \"item_3\": \"Austin3\", \"item_4\": \"Texas4\" } ]"
var array = []
do {
array = try NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding)!, options:.AllowFragments) as! NSArray
} catch {
print(error)
}
if let unwrappedValue = (array[0]["item_1"]){
print(unwrappedValue)
}
It will return an optional so it would be nice to use if let statement to unwrap value
For your usage this code should be like this :
if let JSON = response.result.value {
if let unwrappedValue = (JSON[0]["item_1"]){
print(unwrappedValue)
}
}