Parse JSON array with Swiftyjson in Swift 2.3 - ios

I'm working with Swiftyjson in Swift 2.3. I've been able to parse json arrays into a UITableview with no problem until I got the following json response:
{
"CAR": [
{
"SID": "1",
"NAME": "BMW",
},
{
"SID": "2",
"NAME": "MERCEDES",
},
],
"BIKE": [
{
"SID": "3",
"NAME": "KAWASAKI",
},
{
"SID": "4",
"NAME": "HONDA",
},
]
}
QUESTION How do I parse "CAR" and "BIKE" into tableview sections and have their items under each section? I've managed to get the "keys" using:
// Other Code
let json = JSON(data)
for (key, subJson) in json {
self.array.append(key)
}
print(self.array)
["CAR", "BIKE"]
I wanted to know how to loop through each section and get their items properly. Any help would be great!

Since you haven't shown where you are getting your json data from, I have tested this by having your JSON above in a .json file. Also this doesn't use SwiftyJSON but you will be able to modify the syntax to get the same result.
class TableViewController: UITableViewController {
var tableData = Dictionary<String,Array<Dictionary<String,String>>>()
var sections = Array<String>()
override func viewDidLoad() {
super.viewDidLoad()
load(file: "document")
}
func load(file:String) {
guard let path = Bundle.main.path(forResource: file, ofType: "json") else { return }
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { return }
guard let json = try? JSONSerialization.jsonObject(with: data) else { return }
guard let dict = json as? Dictionary<String,Array<Dictionary<String,String>>> else { return }
self.tableData = dict
self.sections = dict.keys.sorted()
self.tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let key = self.section[section]
return key
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let key = self.section[indexPath.section]
return self.tableData[key]?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
let key = self.section[indexPath.section]
let cellData = self.tableData[key]?[indexPath.row]
cell.textLabel?.text = cellData?["NAME"]
cell.detailTextLabel?.text = "SID: \(cellData?["SID"] ?? "Unknown")"
return cell
}
}
This is how it looks on an iPhone.

Related

Could not cast value of type (0x10ca9be10) to 'NSString' (0x7fff86d8bbb0)

Hello good afternoon to everyone.
I hope you are doing very well despite the situation we are going through.
I tell you my problem.
I am trying to save in an array, a series of data that is selected from a tableView through a JSON.
That is, the tableView shows some data available to select, the ones that are selected I want to save them in an array but when I select a data in the tableView my app crashes and shows me a breakpoint "Thread 1: signal SIGABRT"
And in the console I get this:
Could not cast value of type 'MallConcierge.DetallesIntereses' (0x10ca9be10) to 'NSString' (0x7fff86d8bbb0).
I hope you can help me, I attach the classes from where I download the data, the details and the class where I connect the tableView.
InteresesModelo.swift (in this class is where I download the data in JSON)
import UIKit
protocol InteresesModeloProtocol: class{
func interesesDownload (interest: NSArray)
}
class InteresesModelo: NSObject {
weak var delegate: InteresesModeloProtocol!
let urlPath = "http://localhost:8888/mallconcierge/API-movil/interests.php"
func interestDownload(){
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.ephemeral)
URLCache.shared.removeAllCachedResponses()
let task = defaultSession.dataTask(with: url){
(data, response, error) in
if error != nil{
print("Error al descargar datos")
}else{
print("Datos descargados")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data){
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSArray
}catch let error as NSError{
print(error)
}
var jsonElement = NSDictionary()
let detalles = NSMutableArray()
for i in 0 ..< jsonResult.count{
jsonElement = jsonResult[i] as! NSDictionary
let detalle = DetallesIntereses()
let idInteres = jsonElement["idInteres"]
let nombreInteres = jsonElement["interesNombre"]
detalle.idInteres = idInteres as? String
detalle.nombreInteres = nombreInteres as? String
detalles.add(detalle)
}
DispatchQueue.main.async(execute: { ()-> Void in
self.delegate.interesesDownload(interest: detalles)
})
}
}
DetallesIntereses.swift
import UIKit
class DetallesIntereses: NSObject {
var idInteres: String?
var nombreInteres: String?
override init() {
}
init(idInteres: String, nombreInteres:String) {
self.idInteres = idInteres
self.nombreInteres = nombreInteres
}
override var description: String{
return "idInteres: \(idInteres), nombreInteres: \(nombreInteres)"
}
}
InteresesViewController.swift
import UIKit
class InteresesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, InteresesModeloProtocol {
var selectIntereses = [String]()
var feedInterests: NSArray = NSArray()
// var selectInterests: DetallesIntereses = DetallesIntereses()
var items=[String]()
#IBOutlet var listaInteresesTableView: UITableView!
func interesesDownload(interest: NSArray) {
feedInterests = interest
self.listaInteresesTableView.reloadData()
}
override func viewDidLoad() {
self.listaInteresesTableView.isEditing = true
self.listaInteresesTableView.allowsMultipleSelectionDuringEditing = true
self.listaInteresesTableView.delegate = self
self.listaInteresesTableView.dataSource = self
let interesesModelo = InteresesModelo()
interesesModelo.delegate = self
interesesModelo.interestDownload()
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedInterests.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "celInterests", for: indexPath) as! InteresesTableViewCell
let interest: DetallesIntereses = feedInterests[indexPath.row] as! DetallesIntereses
cell.lblNombreIntereses!.text = interest.nombreInteres
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectDeselectCell(tableView: listaInteresesTableView, indexPath: indexPath)
print("Seleccionado")
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.selectDeselectCell(tableView: listaInteresesTableView, indexPath: indexPath)
print("Deseleccionado")
}
func selectDeselectCell(tableView: UITableView, indexPath: IndexPath){
self.selectIntereses.removeAll()
if let arr = listaInteresesTableView.indexPathsForSelectedRows{
for index in arr{
selectIntereses.append(feedInterests[indexPath.row] as! String)
}
}
print(selectIntereses)
}
#IBAction func seleccionarIntereses(_ sender: Any){
print(selectIntereses)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
The JSON
[
{
"idInteres": "1",
"interesNombre": "Moda Mujer"
},
{
"idInteres": "3",
"interesNombre": "Moda Hombre"
},
{
"idInteres": "4",
"interesNombre": "Belleza"
},
{
"idInteres": "5",
"interesNombre": "Relojes y Joyería"
},
{
"idInteres": "6",
"interesNombre": "Hogar/Interiorismo"
},
{
"idInteres": "7",
"interesNombre": "Gastronomía"
},
{
"idInteres": "8",
"interesNombre": "Entretenimiento"
},
{
"idInteres": "9",
"interesNombre": "Wellness"
}
]
I hope you can help me, please.
I thank you all
There's lots of little stuff going on here. I've tried to highlight as I make edits with //<-- Here.
By far the biggest issue is using the untyped Objective-C NSArray instead of using a typed Swift array. By switching to that, you can get useful type errors.
I had to make a couple of assumptions about what you wanted to do, but this should get you started.
I've left the original JSON decoding for the most part, but I'd strongly suggest you look into using Codable instead of JSONSerialization unless you have a compelling reason not to.
protocol InteresesModeloProtocol : AnyObject {
func interesesDownload (interest: [DetallesIntereses]) //<-- Here
}
class InteresesModelo: NSObject {
weak var delegate: InteresesModeloProtocol!
let urlPath = "http://localhost:8888/mallconcierge/API-movil/interests.php"
func interestDownload(){
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.ephemeral)
URLCache.shared.removeAllCachedResponses()
let task = defaultSession.dataTask(with: url){
(data, response, error) in
if error != nil{
print("Error al descargar datos")
}else{
print("Datos descargados")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data){
var jsonResult = [[String:String]]()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [[String : String]]
}catch let error as NSError{
print(error)
}
let detalles = jsonResult.map { jsonElement -> DetallesIntereses in
let detalle = DetallesIntereses(idInteres: jsonElement["idInteres"], nombreInteres: jsonElement["interesNombre"])
return detalle
}
DispatchQueue.main.async {
self.delegate.interesesDownload(interest: detalles)
}
}
}
struct DetallesIntereses { //<-- Here -- no reason for this to be an `NSObject`
var idInteres: String?
var nombreInteres: String?
}
class InteresesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, InteresesModeloProtocol {
var selectIntereses = [DetallesIntereses]() //<-- Here
var feedInterests: [DetallesIntereses] = [] //<-- Here
var items = [String]()
#IBOutlet var listaInteresesTableView: UITableView!
func interesesDownload(interest: [DetallesIntereses]) { //<-- Here
feedInterests = interest //<-- Here
self.listaInteresesTableView.reloadData()
}
override func viewDidLoad() {
self.listaInteresesTableView.isEditing = true
self.listaInteresesTableView.allowsMultipleSelectionDuringEditing = true
self.listaInteresesTableView.delegate = self
self.listaInteresesTableView.dataSource = self
let interesesModelo = InteresesModelo()
interesesModelo.delegate = self
interesesModelo.interestDownload()
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedInterests.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "celInterests", for: indexPath) as! InteresesTableViewCell
let interest: DetallesIntereses = feedInterests[indexPath.row] //<-- Here
cell.lblNombreIntereses!.text = interest.nombreInteres
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectDeselectCell(tableView: listaInteresesTableView, indexPath: indexPath)
print("Seleccionado")
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.selectDeselectCell(tableView: listaInteresesTableView, indexPath: indexPath)
print("Deseleccionado")
}
func selectDeselectCell(tableView: UITableView, indexPath: IndexPath){
self.selectIntereses.removeAll()
selectIntereses.append(feedInterests[indexPath.row]) //<-- Here
print(selectIntereses)
}
#IBAction func seleccionarIntereses(_ sender: Any){
print(selectIntereses)
}
}

Parse JSON Using Decodable into TableView Sections with an Array inside an Array

I am attempting to parse data from an api into a tableView with Sections. The end result would be a section title that corresponds with a month and rows with lists of videos that were posted for the month. The videos may not include a poster or description.
I tried to implement a for in loop function to update the model after retrieving the data, which worked great until I started trying to implement sections. I can print the json response to the console and receive the full response.
Here is a sample of the original JSON Structure:
{
"page": {
"type": "videos",
"sections": [{
"title": "September",
"videos": [{
"title": "Some Video",
"description": "Video Description",
"poster": "",
"url": "url"
}]
}, {
"title": "August 2019",
"videos": [{
"title": "Some Video",
"description": "",
"poster": "Some Image",
"url": "url"
}, {
"title": "Some Video",
"description": "No Description",
"poster"",
"url": "url"
}]
}]
}
}
Here is my Model:
struct Root: Decodable {
let page: Page
}
struct Page: Decodable {
let type: String
let sections: [VideoSection]
}
struct VideoSection: Decodable {
let title: String
let videos: [Video]
}
struct Video: Decodable {
let videoTitle: String
let videoDescription: String?
let poster: String?
let url: String
enum CodingKeys: String, CodingKey {
case videoTitle = "title"
case videoDescription = "description"
case poster = "poster"
case url = "url"
}
}
Here is may Networking call with Parsing:
func getVideoData(url: String){
guard let videoUrl = URL(string: "Video_URL") else { return }
URLSession.shared.dataTask(with: videoUrl) { (data, response, error) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let responseData = try decoder.decode(Root.self, from: data)
DispatchQueue.main.async {
self.videoTableView.reloadData()
}
} catch let err {
print("Error", err)
}
}.resume()
}
Here is my tableView:
var allvideosArray = [Video]()
var allSectionsArray = [VideoSection]()
var rootArray: Root?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customVideoCell", for: indexPath) as! CustomVideoCell
cell.videoDescriptionPlaceholder.text = Video.CodingKeys.videoDescription.rawValue
cell.videoTitlePlaceholder.text = Video.CodingKeys.videoTitle.rawValue
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return allSectionsArray[section].title
}
func numberOfSections(in tableView: UITableView) -> Int {
return allSectionsArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allvideosArray.count
}
When I attempt to print(responseData.page.sections.videos) I receive the error "Value of type'[VideoSection]' has no member 'videos,' which leads me to believe the issue has to do with the [videos] array inside of the [sections] array.
You can try
var page:Page?
let responseData = try decoder.decode(Root.self, from: data)
self.page = responseData.page
DispatchQueue.main.async {
self.videoTableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customVideoCell", for: indexPath) as! CustomVideoCell
let item = page!.sections[indexPath.section].videos[indexPath.row]
cell.videoDescriptionPlaceholder.text = item.videoDescription
cell.videoTitlePlaceholder.text = item.videoTitle
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return page?.sections[section].title
}
func numberOfSections(in tableView: UITableView) -> Int {
return page?.sections.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return page?.sections[section].videos.count ?? 0
}

How to group tableview cells based on field in JSON array

Essentially I have am using JSON data to create an array and form a tableview.
I would like the table cells to be grouped by one of the fields from the JSON array.
This is what the JSON data looks like:
[{"customer":"Customer1","number":"122039120},{"customer":"Customer2","number":"213121423"}]
Each number needs to be grouped by each customer.
How can this be done?
This is how I've implemented the JSON data using the table:
CustomerViewController.swift
import UIKit
class CustomerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FeedCustomerProtocol {
var feedItems: NSArray = NSArray()
var selectedStock : StockCustomer = StockCustomer()
let tableView = UITableView()
#IBOutlet weak var customerItemsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//set delegates and initialize FeedModel
self.tableView.allowsMultipleSelection = true
self.tableView.allowsMultipleSelectionDuringEditing = true
self.customerItemsTableView.delegate = self
self.customerItemsTableView.dataSource = self
let feedCustomer = FeedCustomer()
feedCustomer.delegate = self
feedCustomer.downloadItems()
}
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.customerItemsTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of feed items
print("item feed loaded")
return feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Retrieve cell
let cell = tableView.dequeueReusableCell(withIdentifier: "customerGoods", for: indexPath) as? CheckableTableViewCell
let cellIdentifier: String = "customerGoods"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
// Get the stock to be shown
let item: StockCustomer = feedItems[indexPath.row] as! StockCustomer
// Configure our cell title made up of name and price
let titleStr = [item.number].compactMap { $0 }.joined(separator: " - ")
return myCell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
let cellIdentifier: String = "customerGoods"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
myCell.textLabel?.textAlignment = .left
}
}
FeedCustomer.swift:
import Foundation
protocol FeedCustomerProtocol: class {
func itemsDownloaded(items: NSArray)
}
class FeedCustomer: NSObject, URLSessionDataDelegate {
weak var delegate: FeedCustomerProtocol!
let urlPath = "https://www.example.com/example/test.php"
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Error")
}else {
print("stocks downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let stocks = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let stock = StockCustomer()
//the following insures none of the JsonElement values are nil through optional binding
if let number = jsonElement[“number”] as? String,
let customer = jsonElement["customer"] as? String,
{
stock.customer = customer
stock.number = number
}
stocks.add(stock)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: stocks)
})
}
}
StockCustomer.swift:
import UIKit
class StockCustomer: NSObject {
//properties of a stock
var customer: String?
var number: String?
//empty constructor
override init()
{
}
//construct with #name and #price parameters
init(customer: String) {
self.customer = customer
}
override var description: String {
return "Number: \(String(describing: number)), customer: \(String(describing: customer))"
}
}
You can achieve this by making an array of array. So something like this
[[{"customer": "customer1", "number": "123"}, {"customer": "customer1", "number": "456"}], [{"customer": "customer2", "number": "678"}, {"customer": "customer2", "number": "890"}]]
This is not the only data structure you can use to group. Another possibility is:
{"customer1": [{"customer": "customer1", "number": "123"}, {"customer": "customer1", "number": "456"}], "customer2": [{"customer": "customer2", "number": "678"}, {"customer": "customer2", "number": "890"}]}
Then you can use UITableView sections to group by customers. Section count would be the number of inside arrays and each section would contain as many rows as there are numbers in that inside array.
You can group a sequence based on a particular key using one of the Dictionary initializer,
init(grouping:by:)
The above method init will group the given sequence based on the key you'll provide in its closure.
Also, for parsing such kind of JSON, you can easily use Codable instead of manually doing all the work.
So, for that first make StockCustomer conform to Codable protocol.
class StockCustomer: Codable {
var customer: String?
var number: String?
}
Next you can parse the array like:
func parseJSON(data: Data) {
do {
let items = try JSONDecoder().decode([StockCustomer].self, from: data)
//Grouping the data based on customer
let groupedDict = Dictionary(grouping: items) { $0.customer } //groupedDict is of type - [String? : [StockCustomer]]
self.feedItems = Array(groupedDict.values)
} catch {
print(error.localizedDescription)
}
}
Read about init(grouping:by:) in detail here: https://developer.apple.com/documentation/swift/dictionary/3127163-init
Make the feedItems object in CustomerViewController of type [[StockCustomer]]
Now, you can implement UITableViewDataSource methods as:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customerGoods", for: indexPath) as! CheckableTableViewCell
let items = self.feedItems[indexPath.row]
cell.textLabel?.text = items.compactMap({$0.number}).joined(separator: " - ")
//Configure the cell as per your requirement
return cell
}
Try implementing the approach with all the bits and pieces and let me know in case you face any issues.

Variable from another class

I have a problem when accessing the variable from another class.
I am initializing and modifying variable here
TheResponse Class
import Foundation
import Alamofire
class TheResponse {
typealias JSONStd = [[String : AnyObject]]
var jsonAnswer = [[String:String]]()
var getRes: [[String : String]] {
return jsonAnswer
}
func callAmo(){
let urladdress = "https://api.github.com/users"
Alamofire.request(urladdress).responseJSON(completionHandler: {
response in
//print(response)
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data){
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStd
let counter = readableJSON.count
//Filling the dictionary
for item in 0...counter - 1 {
let login = readableJSON[item]["login"]
let avatar_url = readableJSON[item]["avatar_url"]
let html_url = readableJSON[item]["html_url"]
let id = String(describing: readableJSON[item]["id"])
var dict:[String:AnyObject] = ["login": login!,
"avatar": avatar_url!,
"profile": html_url!,
"id": id as AnyObject]
jsonAnswer.append(dict as! [String : String])
}
}
catch{
print(error)
}
}
}
If I will print somewhere here the jsonAnswer variable, everything looks fine.
But I want to use this variable in my second class
import UIKit
import Alamofire
class TableViewController: UITableViewController {
var resObj = TheResponse()
var jsonData = [[String:String]]()
override func viewDidLoad() {
super.viewDidLoad()
resObj.callAmo{ (jsonAns) -> () in
self.jsonData = jsonAns
// print(self.jsonData)
}
print(self.jsonData)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MainViewCell
return cell
}
}
The problem is that when I want to print the variable in TableViewController class, the variable is empty. As print out I am getting only [].
How should I access the variable to have it as it should be?
The problem is you haven't call callAmo method also, you need to create completion closure with your method, so change your code like this.
func callAmo(completion: ([[String : String]]) -> ()) {
let urladdress = "https://api.github.com/users"
Alamofire.request(urladdress).responseJSON(completionHandler: {
response in
//print(response)
let dic = self.parseData(JSONData: response.data!)
completion(dic)
})
}
Now return the dictionary from parseData methods like this.
func parseData(JSONData : Data) -> [[String: String]]{
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStd
let counter = readableJSON.count
//Filling the dictionary
for item in 0...counter - 1 {
let login = readableJSON[item]["login"]
let avatar_url = readableJSON[item]["avatar_url"]
let html_url = readableJSON[item]["html_url"]
let id = String(describing: readableJSON[item]["id"])
var dict:[String:AnyObject] = ["login": login!,
"avatar": avatar_url!,
"profile": html_url!,
"id": id as AnyObject]
jsonAnswer.append(dict as! [String : String])
}
}
catch{
print(error)
}
return jsonAnswer
}
Now call this method in viewDidLoad of TableViewController like this.
resObj.callAmo{ (jsonAns) -> () in
print(jsonAns)
}
Edit: To get the data in TableViewController do like this
var jsonData = [[Strin:String]]()
override func viewDidLoad() {
super.viewDidLoad()
resObj.callAmo{ (jsonAns) -> () in
self.jsonData = jsonAns
self.tableView.reloadData()
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.jsonData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MainViewCell
return cell
}

How to filter JSON response in XCODE?

situation:
I have a JSON response parsed via SwiftyJSON. And I'm populating table cells with the data. Everything is cool, but now I need to remove some dictionaries from my JSON, and it doesn't let me do that in an any way (loops or other conditions).
Example of received JSON:
{"post-comments" : [
{
"post" : "new",
"_id" : "1",
},
{
"post" : "new",
"_id" : "2",
},
{
"post" : "post with title",
"_id" : "23",
},
{
"post" : "new",
"_id" : "29",
},
{
"post" : "post with title",
"_id" : "90",
},
{
"post" : "post with title",
"_id" : "33",
}
]
}
I'm tryin to get rid of some dictionaries, lets say if "post" === "new" - I need to remove them from my JSON and continue populate my cells with left data.
Completely stuck.. Any ideas would be much appreciated.
here is the complete tableviewcontroller:
class TableViewContr: UITableViewController {
let Comments : String = "http://localhost:3000/api/comments/"
var json : JSON = JSON.null
override func viewDidLoad() {
super.viewDidLoad()
getPostComments(Comments)
}
func getPostComments(getcomments : String) {
Alamofire.request(.GET, getcomments).responseJSON {
response in
guard let data = response.result.value else {
return
}
self.json = JSON(data)
self.tableView.reloadData()
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch self.json["post-comments"].type {
case Type.Array:
return self.json["post-comments"].count
default:
return 1
}
}
func populateFields(cell: TableViewContrCell, index: Int) {
guard let comment = self.json["post-comments"][index]["post"].string else {
return
}
cell.commentContent!.text = comment
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewContrCell
populateFields(cell, index: indexPath.row)
return cell
}
}
This is an approach to parse and filter the JSON data before reloading the table view.
comments is the data source array containing the post-comments dictionaries
class TableViewContr: UITableViewController {
let commentURL : String = "http://localhost:3000/api/comments/"
var comments = [[String:String]]()
override func viewDidLoad() {
super.viewDidLoad()
getPostComments(commentURL)
}
func getPostComments(getcomments : String) {
Alamofire.request(.GET, getcomments).responseJSON {
response in
guard let data = response.result.value else { return }
let jsonData = JSON(data)
let postComments = jsonData["post-comments"].arrayObject as! [[String:String]]
self.comments = postComments.filter{$0["post"] != "new"}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewContrCell
let comment = comments[indexPath.row]
cell.commentContent!.text = comment["post"]!
return cell
}
}

Resources