unable to load JSON data in tableviewcell using Alamofire & SwiftyJSON - swift

I want to load the name & symbol of cryptocurrencies in textLabel & detailTextLabel
TableViewController.swift :-
import UIKit
import Alamofire
import SwiftyJSON
class TableViewController: UITableViewController {
var fetchCoinInfo = [[String: AnyObject]]()
let url = "https://api.coinmarketcap.com/v1/ticker/"
override func viewDidLoad() {
super.viewDidLoad()
getCoinData(url: url)
self.tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return fetchCoinInfo.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
cell.textLabel?.text = fetchCoinInfo[indexPath.row]["name"] as? String
cell.detailTextLabel?.text = fetchCoinInfo[indexPath.row]["symbol"] as? String
return cell
}
Using Alamofire :-
func getCoinData(url: String) {
Alamofire.request(url, method: .get)
.responseJSON { response in
if response.result.isSuccess {
print("Sucess! Got the data")
let coinJSON : JSON = JSON(response.result.value!)
print(coinJSON)
self.updateCoinData(json: coinJSON)
} else {
print("Error: \(String(describing: response.result.error))")
}
}
self.tableView.reloadData()
}
Using SwiftyJSON :-
func updateCoinData(json : JSON) {
if let coinData = json[].arrayObject {
print(coinData)
self.fetchCoinInfo = coinData as! [[String: AnyObject]]
}
else {
print("cannot connect to the server")
}
}
}

put this line in updateCoindata
self.tableView.reloadData()
func updateCoinData(json : JSON) {
if let coinData = json[].arrayObject {
print(coinData)
self.fetchCoinInfo = coinData as! [[String: AnyObject]]
self.tableView.reloadData()
}
else {
print("cannot connect to the server")
}
}

Related

Swift table view and search controller didSelectRowAt index out of range

In Swift, I'm using SearchController and TableView with search API below.
https://developers.giphy.com/docs/api/endpoint#search
api.giphy.com/v1/gifs/search
When I input to SearchController field, TableView normally reloaded(autocompleted search keywords appear). But when I select row of TableView, 'Index out of range' error(in my ViewModel) occurred in some situation and I can't figure out what is cause.
Error occurred line
func searchKeyword(indexPath: Int) -> String? in ViewModel
This is my code.
ViewController
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let count = self.viewModel?.resultsCount() else { return 0 }
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = searchTableView.dequeueReusableCell(withIdentifier: "CellID", for: indexPath) as? searchTableViewCell else { return UITableViewCell() }
guard let result = self.viewModel?.selectedKeyword(at: indexPath.row) else { return UITableViewCell() }
cell.configureCell(result: result.name)
return cell
}
}
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
guard let text = searchController.searchBar.text?.lowercased() else { return }
self.viewModel?.fetchKeywords(searchKeyword: text)
self.searchTableView.reloadData()
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "NextViewControllerID") as? NextViewController else { return }
guard let result = self.viewModel?.searchKeyword(indexPath: indexPath.row) else { return }
nextViewController.showNextViewController(with: NextViewModel(keyword: result))
self.navigationController?.pushViewController(nextViewController.show, animated: true)
}
}
extension ViewController: UISearchResultsUpdating {
func updateResults(for searchController: UISearchController) {
guard let text = searchController.searchBar.text?.lowercased() else { return }
self.viewModel?.fetchKeywords(searchKeyword: text)
self.searchResults.reloadData()
}
}
ViewModel
func fetchKeywords(searchKeyword: String) {
self.useCase.fetchKeywords(searchKeyword: searchKeyword, paginationCount: 5) { error, result in
if let error = error {
self.error = error
}
if let result = result {
self.results = result.searchKeywords
}
}
}
func resultsCount() -> Int {
guard let count = self.results?.count else { return 0 }
return count
}
// Fatal error: Index out of range
func searchKeyword(indexPath: Int) -> String? {
guard let results = results else { return nil }
return results[indexPath].name
}
func selectedKeyword(at indexPath: Int) -> Keyword? {
guard let results = self.results else { return nil }
return results[indexPath]
}

I want to get firestore data in dequeueReusableCell

I rewrote all the text and now I got the code I wanted to realize.
It can not be displayed on the tableCell, and the layout also collapses. I am sorry that the code and the body I wrote are not explained enough.
guard let userID = Auth.auth (). currentUser? .uid I want to always acquire userID with else {return}.
// guard let docSnapshot = querySnapshot, document.exists else {return}
Since an error occurs, it is commented out.
Within viewidLoad of UIViewController
var profDict: [ProfDic] = [] is in the UIViewController.
profUIView is being added to UIViewController.
func getFirebaseData() {
db = Firestore.firestore()
guard let userID = Auth.auth().currentUser?.uid else {return}
let ref = db.collection("users").document(userID)
ref.getDocument{ (document, error) in
if let document = document {
// guard let docSnapshot = querySnapshot, document.exists else {return}
if let prof = ProfDic(dictionary: document.data()!) {
self.profDict.append(prof)
print("Document data \(document.data())")
}
}else{
print("Document does not exist")
}
self.profUIView.tableView1.reloadData()
}
}
tableView1 has been added to ProfUIView.
class ProfUIView: UIView, UITableViewDelegate, UITableViewDataSource {
//omission...
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blue
addSubview(tableView1)
tableView1.anchor(top: //omission...
sections = [
Section(type: .prof_Sec, items: [.prof]),
Section(type: .link_Sec, items: [.link]),
Section(type: .hoge_Sec, items: [.hoge0])
]
tableView1.register(TableCell0.self, forCellReuseIdentifier: TableCellId0)
tableView1.register(TableCell3.self, forCellReuseIdentifier: TableCellId3)
tableView1.register(TableCell5.self, forCellReuseIdentifier: TableCellId5)
tableView1.delegate = self
tableView1.dataSource = self
}
var tableView1:UITableView = {
let table = UITableView()
table.backgroundColor = .gray
return table
}()
//omission
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (baseVC?.profDict.count)!//sections[section].items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch sections[indexPath.section].items[indexPath.row] {
case .prof:
let cell0 = tableView.dequeueReusableCell(withIdentifier: TableCellId0, for: indexPath) as? TableCell0
cell0?.nameLabel.text = baseVC?.profDict[indexPath.row].userName
return cell0!
}
//omission...
}
}
Additional notes
import Foundation
import FirebaseFirestore
struct ProfDic {
var userName :String
var dictionary:[String:Any] {
return
["userName" : userName
]
}
}
extension ProfDic {
init?(dictionary:[String:Any]) {
guard let userName = dictionary["userName"] as? String
else {return nil}
self.init(userName: userName as String)
}
}
enter image description here
First create an empty array of ProfDic elements:
var profDict: [ProfDic] = []
Then create a function to load your Firebase Data:
func getFirebaseData() {
db = Firestore.firestore()
let userRef = db.collection("users").getDocuments() {
[weak self] (querySnapshot, error) in
for document in querySnapshot!.documents {
guard let docSnapshot = docSnapshot, docSnapshot.exists else {return}
if let prof = ProfDic(dictionary: docSnapshot.data()!) {
profDict.append(prof)
}
}
tableView.reloadData()
}
}
Call this function in viewDidLoad or viewDidAppear.
Then in tableView cellForRowAt you access your data like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch sections[indexPath.section].items[indexPath.row] {
case .prof:
let cell = tableView.dequeueReusableCell(withIdentifier: TableCellId, for: indexPath) as? TableCell
cell?.nameLabel.text = profDict[indexPath.row].userName
return cell!
}
}
EDIT:
Also in numberOfRowsInSection:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return profDict.count
}

How to use swiftyJson to get arrayvalue in TableView?

I use swiftyJson to parse data and, but do not know how to parse array.
Here is code.
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var json:JSON = JSON.null
var urlSession = URLSession(configuration: .default)
#IBOutlet weak var myTableView: UITableView!
var pokamon = [[String:AnyObject]]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pokamon.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
var dict = pokamon[indexPath.row]
cell.nameLbl.text = dict["name"] as? String
cell.typesLbl.text = dict["types"]?[0] as? String
cell.hpLbl.text = dict["hp"] as? String
cell.subtypeLbl.text = dict["subtype"] as? String
if let image = URL(string: dict["imageUrl"] as! String){
let task = urlSession.downloadTask(with: image) { (url, repsponse, error) in
if error != nil{
print("sorry")
return
}
if let okURL = url{
do{
let downloadImage = UIImage(data: try Data(contentsOf: okURL))
DispatchQueue.main.async {
cell.myImage.image = downloadImage
}
}catch{
print("error")
}
}
}
task.resume()
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 224
}
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
Alamofire.request("https://api.pokemontcg.io/v1/cards").responseJSON(completionHandler: { response in
if response.result.isSuccess {
let json:JSON = try! JSON(data: response.data!)
let swiftyJsonVar = JSON(response.result.value!)
if let resData = swiftyJsonVar["cards"].arrayObject{
self.pokamon = resData as! [[String:AnyObject]]
}
if self.pokamon.count > 0{
self.myTableView.reloadData()
}
} else {
print("error: \(response.error)")
}
})
}
}
From cellForRowAt in tableView, it shows "Ambiguous use of 'subscript'" with below code, have no idea how to solve it. The rest like "name", "hp", and "subtype" are no problem!
cell.typesLbl.text = dict["types"]?[0] as? String
Could anyone help me with this error?
Thanks!
The compiler must know the type of any subscripted object. Tell the compiler that you expect an array of strings.
cell.typesLbl.text = (dict["types"] as? [String])?.first
In Swift 3+ all JSON values are Any not AnyObject so declare the array
var pokamon = [[String:Any]]()

Xcode tableview not displaying firebase objects

I am currently trying to display firebase objects in my tableview. However, I am only getting empty prototype cells. Thanks if you can take a glance at it!
import UIKit
import Firebase
class UsersTableViewController: UITableViewController {
var user = [User]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getusers() {
let userID = Auth.auth().currentUser?.uid
let rootRef = Database.database().reference()
let query = rootRef.child("users").queryOrdered(byChild: "fullname")
query.observe(.value) { (snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
if let value = child.value as? NSDictionary {
let userToShow = User()
let fullname = value["fullname"] as? String ?? "Name not found"
let uid = value["uid"] as? String ?? "uid not found"
userToShow.fullname = fullname
userToShow.userID = uid
self.user.append(userToShow)
DispatchQueue.main.async { self.tableView.reloadData() }
}
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return user.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! TableViewCell
cell.nameLabel.text = self.user[indexPath.row].fullname
cell.userID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
return cell
}
}
extension UIImageView {
#objc func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}}
Thanks again for anyone willing to help! I am currently using Swift 4 with Google's Firebase API.
p.s. I know that I have connected delegate and dataSource. I am also sure that I have properly titled my Identifier. Thanks!

why is my data not showing in the tableview?

Printing out the data in the console works just fine. In viewdidload method the array count is also fine. But if i use any of the code outside viewdidload its not working. Im trying to populate a table with two labels in each cell (airline and price) but none of the data is displaying and when i try out in the console arrayOfFlights.price.count (for example) it prints out 0 as if its empty.
Data:
import Foundation
class FlightDataModel {
var airline: String?
var price: String?
init(airline: String?, price: String?) {
self.airline = airline
self.price = price
}
}
controller.swift
import Foundation
import UIKit
class FlightsController: UITableViewController, UITableViewDataSource {
var arrayOfFlights : [FlightDataModel] = [FlightDataModel]()
var startpoint:String!
var endpoint:String!
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrayOfFlights.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as myCustomTableViewCell
cell.airlineLabel.text = arrayOfFlights[indexPath.row].airline
cell.priceLabel.text = arrayOfFlights[indexPath.row].price
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// json request to api
let qpxRequest = Router.QPXRequest()
request(qpxRequest).responseJSON { (request, response, json, error) -> Void in
if json != nil {
//insert airline data into arrayOfFlights
if let myJSON = json as? [String:AnyObject] {
if let trips = myJSON["trips"] as? [String:AnyObject] {
if let data = trips["data"] as? [String:AnyObject] {
if let carriers = data["carrier"] as? [[String:String]] {
for (index, carrierName) in enumerate(carriers) {
var myFlight = FlightDataModel(airline: carrierName["name"] as String!, price:nil)
self.arrayOfFlights.append(myFlight)
}
}
}
if let tripOptions = trips["tripOption"] as? [[String:AnyObject]] {
for (index, tripOption) in enumerate(tripOptions) {
self.arrayOfFlights[index].price = tripOption["saleTotal"] as String!
}
}
}
}
}
} // end api request
} //end viewdidload
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
}
Make sure your class is set as dataSource of your tableView
And call the method tableView.reloadData() when you are done with the data parsing.