tableView Cell not displaying data, What's the issue? (Swift 3) - ios

So I have a view controller that is parsing some bitcoin price data. The function successfully responds and parses the data, but I cannot seem to get it to display in tableView.
I have already tested the outlets and identities via a test cell, which does work.
What am I doing wrong?
Code: `
import UIKit
import Alamofire
import AlamofireObjectMapper
import ObjectMapper
class Response: Mappable{
var data: [Amount]?
required init?(map: Map){
}
func mapping(map: Map) {
data <- map["data"]
}
}
class Amount: Mappable {
var data : String?
required init?(map: Map){
}
func mapping(map: Map) {
data <- map["data.amount"]
}
}
class ViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource {
var mount = [String]()
var am = [String]()
#IBOutlet var tableView: UITableView!
func Call_bitcoin() {
let url = "https://api.coinbase.com/v2/prices/BTC-USD/buy"
Alamofire.request(url).responseObject{ (response: DataResponse<Amount>) in
let mount = response.result.value
let am = mount?.data
self.tableView.reloadData()
return
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.delegate = self
tableView.dataSource = self
Call_bitcoin()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return am.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped cell number \(indexPath.row).")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
print(am)
cell.textLabel?.text = am[indexPath.row]
return cell
}
}
`

You want to add elements in your Call_bitcoin() function but you are doing it wrong. You have already created var am = [String](). So you don't need to use let am = mount?.data. You could add your data in your am variable which is already created. You need to change some of your code lines in Call_bitcoin() function:
From:
let mount = response.result.value
let am = mount?.data
To:
let mount = response.result.value
am.append(mount?.data) // This part should be set by your 'mount?.data' value type

Your JSON not returning array, it's having dictionary.that why you get
am.count = 0
Solve first your data and put data into the array.
{"data":{"amount":"2414.88","currency":"USD"},"warnings":[{"id":"missing_version","message":"Please supply API version (YYYY-MM-DD) as CB-VERSION header","url":"https://developers.coinbase.com/api#versioning"}]}

Related

Getting collection and saving it into array object in firestore swift

I'm trying to save collection into an array of objects called List, and the retrieving is been called in viewdidload by the function loadfirebase. So it actually retrieves the data from firebase and prints it but it doesn't save it in the array. I think it is something that deals with closure but not sure how to fix it.
//
// ContactList.swift
// Socket
//
// Created by dalal aljassem on 12/16/21.
//
import UIKit
import FirebaseFirestore
import FirebaseStorage
class ContactList: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let storage = Storage.storage().reference()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return List.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell" , for:indexPath)
var currentname = List[indexPath.row]
cell.textLabel?.text = currentname.name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
print("some action will happen when i tap here")
}
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadfirebase()
print("**************",List)
}
}
let database = Firestore.firestore()
func loadfirebase()
{
let contactdataRef = database.collection("ContactData")
contactdataRef.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
// var currentDoc = document.data()
print("///////////////")
// print("current doc = " , currentDoc)
print("current name = " , document.get("name")!)
print("current image = " , document.get("image")!)
List.append(Contact(name: document.get("name") as! String, image: document.get("image") as! String, number: ""))
print("\(document.documentID) => \(document.data())")
}
}
}}
}
Your List array is never initialized.
You can achieve this with the following code:
var List: [Contact] = []
and I would put this before the declaration of tableView function.

How to display JSON data from API in TableView?

I recieves json data from api and totally confused what should I do next to pass this data to custom cell with imageView and labels in order to update UI in tableView.
Getting JSON
import Foundation
struct Breed: Codable {
let name: String?
let origin: String?
let life_span:String?
let temperament: String?
let description: String?
let wikipedia_url: String?
let image: Image?
}
struct Image: Codable {
let url: String?
}
func getDataFromCatsApi() {
let url = URL(string: "https://api.thecatapi.com/v1/breeds")
let task = URLSession.shared.dataTask(with: url!) { data, _ , error in
let decoder = JSONDecoder()
if let data = data {
let breed = try? decoder.decode([Breed].self, from: data)
print (breed as Any)
} else {
print (error as Any)
}
}
task.resume()
}
All data is printed correctly.
In ViewController I have a tableView with custom cell.
import UIKit
class MainVC: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
title = "Cats"
view.backgroundColor = .systemBackground
getDataFromCatsApi()
}
}
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as? CustomTableViewCell
return cell ?? CustomTableViewCell()
}
}
Class for custom cell. Here I have imageView and labels for displaying data from json.
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var catImageView: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var originLabel: UILabel!
#IBOutlet weak var addToFavButton: UIButton!
}
First of all, you are not returning anything from getDataFromCatsApi(). Since it is an asynchronous call, you have to implement a way to get the values either by using a callback or a delegate. In this case callback would suffice.
Then once you receive a value from the api call, set those values in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) in which you can use cell.nameLabel.text = <received value> and etc.
First of all declare only those properties as optional which can be nil
struct Breed: Decodable {
let name, origin, lifeSpan, temperament, description: String
let wikipediaUrl: String?
let image: Image?
}
struct Image: Decodable {
let url: String?
}
In getDataFromCatsApi add a completion handler
func getDataFromCatsApi(completion: #escaping (Result<[Breed],Error>) -> Void ) {
let url = URL(string: "https://api.thecatapi.com/v1/breeds")
let task = URLSession.shared.dataTask(with: url!) { data, _ , error in
if let error = error { completion(.failure(error)); return }
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
completion(Result { try decoder.decode([Breed].self, from: data!) })
}
task.resume()
}
In MainVC declare a data source array
var cats = [Breed]()
Replace viewDidLoad with
override func viewDidLoad() {
super.viewDidLoad()
title = "Cats"
view.backgroundColor = .systemBackground
getDataFromCatsApi {[unowned self] result in
DispatchQueue.main.async {
switch result {
case .success(let breed):
self.cats = breed
self.tableView.reloadData()
case .failure(let error): print(error)
}
}
}
}
and the table view datasources methods with
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cats.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as! CustomTableViewCell
let cat = cats[indexPath.row]
cell.nameLabel = cat.name
cell.originLabel = cat.origin
}
}
To load the pictures is beyond the scope of the question. There are libraries like SDWebImage or Kingfisher to load and cache images asynchronously.
I have attached the code please check
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Breed.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as? CustomTableViewCell
cell.nameLabel.text = Breed[indexPath.row].name // see here
return cell ?? CustomTableViewCell()
}
}

How to get the child from a parent in a parent child relationship for realm in swift

What i am trying to do is access a child when I have the parent in realm. In this example I have a simple table view that I want to populate with the child when accessing the parent. The part I am struggling with is trying to find the child when accessing the parent.
This is the viewController that i am trying to access the children:
import UIKit
import Realm
import RealmSwift
class OtherViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var otherTableView: UITableView!
var realm: Realm!
var realmedData = ""
var realmList: Results<Realmed> {
get {
return realm.objects(Realmed.self)
}
}
var realmTwoList: Results<RealmTwo> {
get {
return realm.objects(RealmTwo.self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
realm = try! Realm()
self.otherTableView.delegate = self
self.otherTableView.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var counted = realm.objects(RealmTwo.self).filter("realmLbl == %#", realmedData)
return counted.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
cell.otherLbl.text = "\(items.spanish)"
}
}
return cell
}
}
this is another method I tried for the cell for row at:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
cell.otherLbl.text = "\(items.spanish)"
}
}
return cell
}
this is the parent realm class:
import Foundation
import Realm
import RealmSwift
class Realmed: Object {
#objc dynamic var label = ""
#objc dynamic var romanNum = ""
#objc dynamic var txt = ""
let realmTwo = List<RealmTwo>()
override static func primaryKey() -> String {
return "label"
}
convenience init(label: String, romanNum: String, txt: String) {
self.init()
self.label = label
self.romanNum = romanNum
self.txt = txt
}
}
and this is the realm class for the child:
import Foundation
import UIKit
import Realm
import RealmSwift
class RealmTwo: Object {
#objc dynamic var realmLbl = String()
#objc dynamic var spanish = String()
#objc dynamic var french = String()
let realmed = LinkingObjects(fromType: Realmed.self, property: "realmTwo")
convenience init(realmLbl: String, spanish: String, french: String) {
self.init()
self.realmLbl = realmLbl
self.spanish = spanish
self.french = french
}
}
When I run this as is, the only thing that populates the tableview is the last value saved to realm.
In this example the children are the strings: "Uno" and "Un", and I want them both to populate the tableView, but the tableView is only populated by the last value in realm, in this case, "Un".
Through research I found out that it is because I am looping through the realm value to get the child. The problem with that is that the only way to get to the child is with the loop but then it can't populate a tableView. It seems like a lose-lose situation.
What I am curious about is how to access the child when you have a parent in realm so that I am able to populate a tableView.
If you need anything please ask. Thank you
i think I got something. I figured that what I needed was an array, and it seems that it is unwise to change List to an Array, so what i did was get the content from the List and put it in an array, since it is easier to put data in a tableview from an array.
This is the array that i created:
var realmArr = [String]()
and this is the cell for row at for the tableView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
self.realmArr.append(items.spanish)
}
}
cell.otherLbl.text = "\(realmArr[indexPath.row])"
return cell
}
I am not sure if this is okay, but it is the only thing that I can think of.
Thank you for all the help.
Let me address this at a high level with a few code snippets. The question is using Objects so let's take a more concrete example of Person and Dog. In this example we have a list of Person Objects each one owning one dog. So we have a single direction relationship
First we have a Person and Dog class
class DogClass: Object {
#objc dynamic var name: String = ""
}
class PersonClass: Object {
#objc dynamic var name: String = ""
#objc dynamic var dog: DogClass?
}
Here's a viewController class that contains a tableView of people
class peopleVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
var peopleResults: Results<PersonClass>!
override func viewDidLoad() {
super.viewDidLoad()
let realm = RealmService //or however you talk to your realm
self.tableView.delegate = self
self.tableView.dataSource = self
self.peopleResults = realm.objects(PersonClass.self) //loads Person objects
self.tableView.reloadData() //shows the list
}
and within that class, the tableView delegate methods that populate our tableview and handle a tap on a row
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peopleResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath as IndexPath)
let row = indexPath.row
let person = self.peopleResults[row]
cell.textLabel?.text = person.name
return cell
}
//when a row is tapped we need to determine the row, which will be included
// in the indexPath property with indexPath.row
// From there get the object from the dataSource array via it's row index
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let row = indexPath.row
let person = self.peopleResults[row]
let dog = person.dog
//at this point you have the dog object and you could print the name
print(dog.name)
//or pass it to a detail view via a segue etc
}

JSON data on UITableView

I managed to include this API from America FAA website in order to download the NOTAM for a pilot. I manage to send the request of the param "api key, location, state". I get back my JSON data and it works fine. Now my problem is I want to display on a tableView one item of the array that I got back in JSON format, is the item called 'all'.
I created the IBOutlet. I gave the cell identifier, but I'm stuck here
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//Constants
let notamUrl = "https://v4p4sz5ijk.execute-api.us-east-1.amazonaws.com/anbdata/states/notams/notams-realtime-list"
let api_key = "mykey"
let notamModel = ModelloNotam()
#IBOutlet weak var tableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return //????????? i dont know
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath)
// ????????? i dont know
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate=self
tableView.dataSource=self
func getNOTAM (url:String,parameters:[String:String]){
Alamofire.request(url, method: .get, parameters: parameters).responseJSON {
response in
if response.result.isSuccess{
let notamJSON : JSON = JSON (response.result.value!)
self.displayNotam(json: notamJSON)
} else{
print("errore connessione\(response.result.error)")
}
}
}
var locations = "VMMC"
var state = "CHN"
let params : [String : String] = ["locations" : locations, "state" : state, "api_key" : api_key]
getNOTAM(url: notamUrl, parameters: params)
}
func displayNotam (json:JSON) {
let conta = json.count
for var i in 0...conta {
i = i + 1
notamModel.all = json [i]["all"].stringValue
notamModel.type = json [i]["type"].stringValue
// print("The NOTAM type is \(notamModel.type)")
// print(notamModel.all)
// print("************************")
}
}
}
please refer this tutorial https://www.youtube.com/watch?v=sd7d4eoM54U&t=1857s and model data according to JSON file. networking request goes out of main execution queue.
i solve with this code.!!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellid", for: indexPath)
// let text = array[indexPath.row]
// cell.textLabel?.text=text
(cell.contentView.viewWithTag(1) as! UILabel).text = array[indexPath.row]
(cell.contentView.viewWithTag(2) as! UILabel).text = array2[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
thanks for the help.

ObjectMapper displayed model in TableView Swift

I am new to Swift , i parsing my JSON by using ObjectMapper but I want data displayed in TableView
I do not know how to do that
My Model:
import Foundation
import ObjectMapper
import SwiftyJSON
class AllCnannelModel : Mappable {
var id : Int?
var name: String?
var url : URL?
var picture : URL?
var category_id: Int?
required init?(map: Map) {}
func mapping(map: Map) {
id<-map["id"]
name<-map["name"]
url<-map["url"]
picture<-map["picture"]
category_id<-map["category_id"]
}
}
My TableView :
var name = [String]()
var urlChannel = [URL]()
override func viewDidLoad() {
super.viewDidLoad()
let URL = "http://52.50.138.211:8080/ChanelAPI/chanels"
Alamofire.request(URL).responseArray { (response: DataResponse<[AllCnannelModel]>) in
let channnellArray = response.result.value
if let channnellArray = channnellArray {
for channel in channnellArray {
self.name.append(channel.name!)
}
}
self.tableView.reloadData()
}
}
I can describe one type of data in the array and display:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.name.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = self.name[indexPath.row]
return cell
}
but i want all type of data in one array and display TableViewController
How can you implement?
Did you implemented numberOfSections(in tableView: UITableView) -> Int ?

Resources