How to populate table view with large data - ios

I'm trying to populate a table view with a large data. However, my tableview can only display 20 string objects. How do I simply display the rest of the data and update the table view each time the user scrolls to the end?
var people = [People]()
let configureSession = URLSessionConfiguration.default
let session = URLSession(configuration: configure)
//Setup the Api Key...
let apiKey = "https://congress.api.sunlightfoundation.com/legislators?apikey=(//Api Key here...)"
if error != nil{
print("ERROR: \(error?.localizedDescription)")
return
} else if let jsonData = data {
do{
let parsedJSON = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String: AnyObject]
guard let results = parsedJSON["results"] as? [[String: AnyObject]] else {return}
for result in results{
let name = myClass()
name.firstName = result["first_name"] as! String
self.people.append(name)
}
DispatchQueue.main.async {
//Reload the data
self.table.reloadData()
}
} catch let error as NSError{
print(error)
}
}
}).resume()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell.textLabel?.text = people[indexPath.row] //Only displays 20... Need to display more!
return cell!
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//Code to display the rest of the data goes here?
}

Make sure you return the correct value in numberOfRowsInSection method:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myLargeData.count
}
With provided myLargeData array there should be 30 rows in your tableView

You can use number of rows in section delegate of table view delegate to handle the more data in array.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return yourarray.count
}

Related

How to parse JSON to the tableView in Swift?

Please give me advise, I can not figure out how to parse data in a table view properly. My goal is to make a tableView with all continents, not just with one "Africa" cell.
Here is my model:
struct ContinentRoot: Codable {
let links: ContinentMiddle
}
struct ContinentMiddle: Codable {
let continentItems: [ContinentsResponse]
}
struct ContinentsResponse: Codable {
let name: String
let href: String
}
In ViewController I add tableView, continentsArray ([ContinentRoot]) and do some regular things for networking.
I guess that the problem may be here, because in the networking method everything seems normal:
private func getContinentsList() {
guard let url = URL(string: "https://api.teleport.org/api/continents/") else { fatalError("URL failed")}
URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
if let data = data {
guard let continent = try? JSONDecoder().decode(ContinentRoot.self, from: data) else { fatalError("DecodingError \(error!)") // REMEMBER: the highest struct
}
self?.continentsArray.append(continent)
}
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return continentsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContinentsTableViewController", for: indexPath)
let model = continentsArray[indexPath.row].links.continentItems[indexPath.row].name
cell.textLabel?.text = model
return cell
}
In viewDidLoad() I call my methods:
getContinentList()
tableView.delegate = self
tableView.dataSource = self
tableView.register(ContinentsTableCell.self, forCellReuseIdentifier: "ContinentsTableViewController")
setupLayout()
Thank you so much for for attention!
According to your attachment design:
if continentsArray is an array of "ContinentRoot" s.
and you want to show the links in the selected ContinentRoot you must first select it, and use it like below:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedContinent.links.continentItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContinentsTableViewController", for: indexPath)
let model = selectedContinent.links.continentItems[indexPath.row].name
cell.textLabel?.text = model
return cell
}
if Not you must use your code and change this line:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContinentsTableViewController", for: indexPath)
let selectedIndex = .zero // or every index you want
let model = continentsArray[indexPath.row].links.continentItems[selectedIndex].name
cell.textLabel?.text = model
return cell
}

dictionary for tableView datasource

I am trying to use a dictionary for a tableView datasource, I am getting an object back from the database that contains a key and an array of values, so a [String: [String]]
var requestedList = [String]()
var keyArr = [String]()
var requestedDictionary = [String: [String]]()
let tQuery = PFQuery(className: "MyClass")
tQuery.whereKey("username", equalTo: PFUser.current()?.username as Any)
tQuery.selectKeys(["descContent", "header"])
do {
let returnedObjects = try tQuery.findObjects()
for object in returnedObjects {
let header = object["header"] as! String
keyArr.append(header)
if let arr = object["descContent"] as! [String]? {
requestedDictionary[header] = arr
requestedList += arr
}
}
} catch {
}
I can't seem to correspond the values correctly to the rows of the tableView however, I was suggested to use an array to store the values which is what I have done with the keyArr. My problem is how do I access the contents of the keys and the corresponding values in the datasource methods?? This is what I have so far but I haven't been able to link the keys and values accordingly
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return requestedList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RequestViewCell", for: indexPath) as! RequestViewCell
cell.descLbl.text = "Your ticket has been requested by \(requestedList[indexPath.row])"
cell.refLbl.text = "for: \(keyArr[indexPath.row])"
cell.leftBtn.tag = (indexPath.section * 100) + indexPath.row
cell.leftBtn.addTarget(self, action: #selector(leftClick(sender:)), for: .touchUpInside)
cell.rightBtn.tag = (indexPath.section * 100) + indexPath.row
cell.rightBtn.addTarget(self, action: #selector(rightClick(sender:)), for: .touchUpInside)
return cell
}
You can turn dictionary into tableView representable data this way.
let requestedDictionary:[String: [String]] = [
"Key-1":["Value-1","Value-2","Value-3","Value-4"],
"Key-A":["Value-X","Value-Y","Value-Z"],
"Key-a":["Value-x","Value-y"],
]
lazy var data:[(key:String,values:[String])] = requestedDictionary.compactMap({(key:$0,values:$1)})
func numberOfSections(in tableView: UITableView) -> Int {
data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].values.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = data[indexPath.section].values[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return data[section].key
}
Hope it helps.

Is there a way to struct a Firestore fields(same name) with arrays and show each array element from each field in TableView

I'm developing a IOS app and I want to show the array Strings from all document fields in table view.
this is my struct for the array.
struct Test{
var car: Array<String>
var dictionary: [String: Any] {
return [
"car":car
]
}
}
extension Test{
init?(dictionary: [String : Any]) {
guard let car = dictionary["car"] as? Array<String>
else { return nil }
self.init(car:car)
}
}
This is my code for fetching the data.
func loadData(){
let db = Firestore.firestore()
db.collection("test").getDocuments(){
querySnapshot, error in
if let error = error {
print("\(error.localizedDescription)")
}else{
self.testArray = querySnapshot!.documents.compactMap({Test(dictionary: $0.data())})
print(self.testArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
And this my tableView code.
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let item = testArray[indexPath.row].car[indexPath.row]
cell.textLabel!.text = ("\(item)")
return cell
Everything seems fine but when run the app, the tableview shows the [0] from the 1st document in the first line, the [1] from the 2nd document in the second line etc. I want to show the whole array from first document then the whole array from 2nd document etc.
You need multiple sections
override func numberOfSections(in tableView: UITableView) -> Int {
return testArray.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray[section].car.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel!.text = testArray[indexPath.section].car[indexPath.row]
return cell
}

How to add new cells and new headers without reloading table in Swift 4?

I have seen a lot of answers with my query, but nothing solved mine. I am opening a new question here.
I have an API, which returns data. I am showing it in the header and the cell. And, there is a load more button too, if the API returns 1 for has_more key. So, when I tap on the load more button I call that API again so that I can get the leftover data, but it refreshes the entire table view as well because I reload the table view.
So, now, what I want to do is I want to append the new cells and headers without reloading the existing table view so that the previous headers and cell in the tableView are not affected.
This is the API function:
func getOverallWinners(has: Int)
{
let params = ["api_token": Constants.USER_INFO["api_token"].rawValue,"has_more": has]
ServiceHelper.sharedInstance.sendRequest(path: "contest-overall-winning", params: params, showSpinner: true)
{ (response, error) in
if error != nil
{
print("Error: \(error.debugDescription)")
}
else
{
self.winnerArr = response["result"].arrayObject as? Array<Dictionary<String,Any>>
self.overallL.text = "$\(String(describing: response["overall"].rawString()!))"
self.winningTbl.beginUpdates()
let indexPath:IndexPath = IndexPath(row:((self.winnerArr?.count)! - 1), section:0)
self.winningTbl.insertRows(at: [indexPath], with: .left)
self.winningTbl.endUpdates()
self.winningTbl.scrollToRow(at: indexPath, at: .bottom, animated: true)
let loadMore = response["has_more"].rawValue as? Int
if loadMore == 0
{
self.constantHeight4LoadMore.constant = 0
}
else
{
self.constantHeight4LoadMore.constant = 40
}
}
}
}
Here are te tableView Delegate:
func numberOfSections(in tableView: UITableView) -> Int {
return (winnerArr?.count)!
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let rowArray = winnerArr![section]["response"] as? Array<Dictionary<String,Any>>
return rowArray!.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
self.prizeArr.removeAll()
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell
let resArr = self.winnerArr![section]["response"]! as? Array<Dictionary<String,Any>>
for prize in resArr!
{
let doubleStr = prize["prize"] as? NSString
self.prizeArr.append((doubleStr?.doubleValue)!)
}
let sumedStr = prizeArr.reduce(0, +)
header.textL[0].text = winnerArr![section]["name"] as? String
header.textL[1].text = "$\(sumedStr)"
header.textL[3].text = "\(String(describing: resArr!.count))"
return header
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "owCell", for: indexPath) as! OWCell
let response = winnerArr![indexPath.section]["response"] as? Array<Dictionary<String,Any>>
cell.collectionL[0].text = (response![indexPath.row]["name"] as! String)
cell.collectionL[1].text = "$\(String(describing:response![indexPath.row]["prize"]!))"
cell.collectionL[2].text = "WIN"
cell.selectionStyle = .none
return cell
}
I tried the beginUpdates() above but nothing worked as every time I will click the load more button I will receive new headers. In those headers there will be the new cells. Can anyone help?
This is not a duplicate beacause that solution is for inserting new rows in a section, but here I have to first create new sections and then add new rows in them. I do not watnt to touch the old sections.

Firebase retrieve multiple data using UITableViewCell (Swift 3)

I'm in trouble with retrieving data from Firebase.
My JSON looks like this:
-user
-contacts
-autoID Value1
-contactName : A
-autoID Value2
-contactName : B
-autoID Value3
-contactName : C
(more contactName is coming, in same structure.)
But I have no idea how to get ALL contactName's Data(A,B,C....) then print in UITableView in Swift3.0
I want to make a result like this :
#In the TableView#
A
B
C
...
But My result is different, Maybe some problem in TableViewCell.swift... but I'm not sure
ViewController.swift :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MoneyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MoneyTableViewCell", for: indexPath) as! MoneyTableViewCell
cell.eachCell()
cell.layoutIfNeeded()
return cell
}
MoneyTableViewCell.swift
func eachCell() {
dbRef = Database.database().reference()
self.dbRef.child("user/contacts").observe(.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
let receiverNameDB = child.childSnapshot(forPath: "contactName").value! as! String
self.nameArray.append(receiverNameDB)
self.nameLabel.text = receiverNameDB
print(self.nameArray)
continue
}
}
})
}
Can Anybody help me please ;)
Update - I solved this problem! Here is my edited code...
Thanks to #Abdul91
The problem was.. I had to get the data from DB first, then put them in the array. After that get each data for tableView.
My edited code will tell you more.
ViewController.swift:
var nameArray:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
getNameDB{ value in
self.nameArray = value
self.tableView.reloadData()
}
tableView.register(UINib(nibName: "MoneyTableViewCell", bundle: nil), forCellReuseIdentifier: "MoneyTableViewCell")
}
//completion is for getting DB value outside of block..
func getNameDB(completion: #escaping (_ value: [String]) -> Void) {
self.dbRef.child("user/contacts").observe(.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
let receiverNameDB = child.childSnapshot(forPath: "contactName").value! as! String
self.nameArray.append(receiverNameDB)
}
completion(self.nameArray)
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.nameArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MoneyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MoneyTableViewCell", for: indexPath) as! MoneyTableViewCell
cell.nameLabel.text = nameArray[(indexPath as NSIndexPath).row]
cell.layoutIfNeeded()
return cell
}

Resources