I'm using an array of instances of the same struct to populate a tableview and I'm stumped by the last item in the array displaying in every cell.
class RoutesViewController: UIViewController, UITableViewDataSource {
#IBOutlet weak var routesTableView: UITableView!
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return type1UnownedRoutesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let routeCell = routesTableView.dequeueReusableCell(withIdentifier: "routeCell") as! RouteTableViewCell
for Flight in type1UnownedRoutesArray {
routeCell.originLabel.text = "Origin: \(Flight.origin)"
routeCell.destinationLabel.text = "Destination: \(Flight.destination)"
routeCell.priceLabel.text = "Price: $\(Flight.popularity)"
}
return routeCell
}
And the struct itself:
struct Flight {
var origin: String
var destination: String
var mileage: Int
var popularity: Int
var isOwned: Bool
}
If I add [indexPath.row] after for Flight in type1UnownedRoutesArray I get Type Flight does not conform to protocol Sequence
Thanks in advance for the help.
The source of your issue is this one in your cellForRow method, you are cycling over all your flights objects in your array, and of course the last value is keeping in your cell, so you need replace this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let routeCell = routesTableView.dequeueReusableCell(withIdentifier: "routeCell") as! RouteTableViewCell
for Flight in type1UnownedRoutesArray {
routeCell.originLabel.text = "Origin: \(Flight.origin)"
routeCell.destinationLabel.text = "Destination: \(Flight.destination)"
routeCell.priceLabel.text = "Price: $\(Flight.popularity)"
}
return routeCell
}
By this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let routeCell = routesTableView.dequeueReusableCell(withIdentifier: "routeCell") as! RouteTableViewCell
let flight = type1UnownedRoutesArray[indexPath.row]
routeCell.originLabel.text = "Origin: \(flight.origin)"
routeCell.destinationLabel.text = "Destination: \(flight.destination)"
routeCell.priceLabel.text = "Price: $\(flight.popularity)"
}
Hope this helps
The problem is you should not be iterating your flights array inside the cellforrow method as it is called once per item in your array.
try this instead
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let routeCell = routesTableView.dequeueReusableCell(withIdentifier: "routeCell") as! RouteTableViewCell
let flight = type1UnownedRoutesArray[indexPath.row]
routeCell.originLabel.text = "Origin: \(flight.origin)"
routeCell.destinationLabel.text = "Destination: \(flight.destination)"
routeCell.priceLabel.text = "Price: $\(flight.popularity)"
return routeCell
}
Related
What I'm trying to do is separate my cells into sections by their Brand
what Ive been able to do so far is pass data of selected items from HomeVC to populate the cells of the CartVC
I am trying to separate the sections by brand, the brand data is a part of the model Items Class (name, brand, imageUrl, price, & weight) and the Items class retrieves data from CloudFirestore to populate the cells of the HomeVC
How would I be able to to separate the cells into sections by their brand, when passed into the CartVC.
So far what I've done seems to fail, because once I pass an item from the HomeVC to the CartVC I only get one header cell, with the brand name of the first item I passed into the CartVC. When I pass more data into the the CartVC all the cells stay in the section of the first item passed when im trying to section off all my CartCells by their brand
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as? HomeCell else { return UITableViewCell() }
let item = itemSetup[indexPath.row]
cell.configure(withItems: item)
cell.addActionHandler = { (option: Int) in
print("Option selected = \(option)")
self.tray.append(Tray(cart: item))
item.selectedOption = option
}
return cell
}
}
class CartViewController: UIViewController {
var items: ProductList!
var sectionModel: [SectionModel] = []
var tray: [Tray] = []
var groupedItems: [String: [Tray]] = [:]
var brandNames: [String] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
groupedItems = Dictionary(grouping: tray, by: {$0.cart.brand})
brandNames = groupedItems.map{$0.key}.sorted()
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = tray[indexPath.row]
cell.configure(withItems: cart.cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeader") as! CartHeader
cartHeader.storeName.text = "Brand: \(tray[section].cart.brand)"
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
class Tray {
var cart: ProductList!
init(cart: ProductList) {
self.cart = cart
}
}
just set your your tableview functions like and you'll have no problem setting things up by section
func numberOfSections(in tableView: UITableView) -> Int {
return brandNames.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let brand = brandNames[section]
return groupedItems[brand]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cartCell = tableView.dequeueReusableCell(withIdentifier: "CartCell") as! CartCell
let brand = brandNames[indexPath.section]
let itemsToDisplay = groupedItems[brand]![indexPath.row]
cartCell.configure(withItems: itemsToDisplay.cart)
return cartCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeader") as! CartHeader
let headerTitle = brandNames[section]
cartHeader.brandName.text = "Brand: \(headerTitle)"
return cartHeader
}
When I run the app only numberOfRowsInSection() method is called. So i place the certain number of break point to the every method but I found that numberOfRowsInSection() is called 4-5 times rest of the method is not get called. Here is my code.
import UIKit
var arrSearch = [[String:Any]]()
class RecentSearchViewController: CustomNavigationViewController {
#IBOutlet var tblSearch: UITableView!
var searchBusVC:SearchBusViewController?
override func viewDidLoad() {
super.viewDidLoad()
if let arr = UserDefault["SearchTo"]{
arrSearch.append(arr as! [String:Any])
}
tblSearch.reloadData()
}
extension RecentSearchViewController: UITableViewDataSource , UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrSearch.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RecentCell") as! RecentCell
cell.selectionStyle = .none
let dict = arrSearch[indexPath.row]
cell.lblFrom.text = (dict["From"] as! String)
cell.lblTo.text = (dict["To"] as! String)
let strDate = Utill.getStringFromDate("EEE MMM dd ,yyyy", date: (dict["fromdate"] as! Date))
cell.lblDate.text = strDate
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let searchvc = self.searchBusVC {
searchvc.setRecentSearch(dict: arrSearch[indexPath.row])
}
self.navigationController?.popViewController(animated: true)
}
}
class RecentCell: UITableViewCell {
#IBOutlet var lblFrom: UILabel!
#IBOutlet var lblTo: UILabel!
#IBOutlet var lblDate: UILabel!
}
I tried many times but it's not going to work for me. Even in console there is no error is shown. Is there any issue with the code?
If numberOfRowsInSection is called, but no other UITableViewDataSource methods are, that must mean that numberOfRowsInSection returns 0. And that must mean that arrSearch is empty. Also, this part of code
if let arr = UserDefault["SearchTo"] {
arrSearch.append(arr as! [String:Any])
}
Should be rewritten. Since you are casting the result of subscript, you can do that as a part of if let, which would also make it safer if the result isn't of [String:Any] type
if let arr = UserDefault["SearchTo"] as? [String:Any] {
arrSearch.append(arr)
}
In short, apparently UserDefault["SearchTo"] returns nil
I want to create a tableview that has two custom cells in it, with the information being pulled from Firebase Database. The first custom cell displays the dates, and the second custom cell displays the events. When I run the app, the tableview is only returning the first custom cell, which is the dates. What would be causing this?
import UIKit
import Firebase
class augustController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var augustController: UITableView!
var ref = DatabaseReference()
var date = [String]()
var event = [String]()
var databaseHandle:DatabaseHandle = 0
var databaseHandle2:DatabaseHandle = 0
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
databaseHandle = ref.child("Events").child("August").child("dates").observe(.childAdded) { (snapshot) in
let post = snapshot.value as? String
if let actualPost = post {
self.date.append(actualPost)
}
}
databaseHandle2 = ref.child("Events").child("August").child("events").observe(.childAdded) { (snapshot) in
let post2 = snapshot.value as? String
if let actualPost2 = post2 {
self.event.append(actualPost2)
self.augustController.reloadData()
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return date.count
}
func tableView2(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return event.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let augustDate = tableView.dequeueReusableCell(withIdentifier: "augustDate") as! dateCell
augustDate.date.text = date[indexPath.row]
return(augustDate)
}
func tableView2(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let augustEvents = tableView.dequeueReusableCell(withIdentifier: "augustEvents") as! eventCell
augustEvents.even.text = event[indexPath.row]
return(augustEvents)
}
}
You implement cellForRow twice , you have to
var itemsArr = [Item]()
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = itemsArr[indexPath.row]
if item.isDate {
let augustDate = tableView.dequeueReusableCell(withIdentifier: "augustDate") as! dateCell
augustDate.date.text = item.content
return augustDate
}
else {
let augustEvents = tableView.dequeueReusableCell(withIdentifier: "augustEvents") as! eventCell
augustEvents.even.text = item.content
return augustEvents
}
}
//
then make it one array and append items of this struct type
struct Item {
var isDate:Bool
var content:String
}
I am loading data into a UITableView. The first load happens properly for the first 10 cells in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
the indexPath.row increments properly and loads the data into the proper cells from the data source. I then implemented a load more when the bottom of the table is reached. Now func tableView is called but it is stuck at indexPath.row = 9. I have implemented a checker in
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
And it appears that the proper number of rows has been added.
Edit: I having issue with the my second uitableview (there are two in this scene) The checker is a print statement that is called and returns the proper uitableView and this happens before the tableView gets stuck at the same value.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.table {
return users2.count
}
else {
print("married barry", tableFeedCount)
return tableFeedCount
}
}
Try following:
Declare boolean
let boolNotMoreData : Bool = true
Append new data to your data source
let arrResponse: [Any]? = (responseObject["news"] as? [Any])
if arrResponse?.count == 0{
boolNotMoreData = false;
}
for dictResponse in arrResponse as! [[String: Any]] {
self.arrDataSource.append(NewsClass(responseDict: dictResponse))
}
self.tblViewNews?.reloadData()
Now fetch new data
private func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == arrNews.count - 1 {
if boolNotMoreData {
currentPage += 1
getYourData()
}
}
}
This worked Successfully
#IBOutlet weak var Submitted: UITableView!
#IBOutlet weak var ViewAssigenment: UITableView!
var Arrayone:[String] = []
var ArrayTwo:[String] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
var count:Int?
if tableView == self.ViewAssigenment
{
count = Arrayone.count
}
else if tableView == self.Submitted
{
count = ArrayTwo.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if tableView == self.ViewAssigenment
{
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewCell") as!
ViewAssigenmentTableViewCell
let obj =Arrayone[indexPath.row]
cell.lblTitle.text = obj.AssTitle
return cell
}
else
{
let cell1 = tableView.dequeueReusableCell(withIdentifier: "Submittcell") as! SubmittedAssigenmentTableViewCell
let obj2 = ArrayTwo[indexPath.row]
cell1.lbltitle.text = obj2.AssTitle
return cell1
}
}
Im really new to Swift, the question is how can I represent values from array in label.
I want a TableView with cells dynamically represent values from array into the labels which will be created in tableView rows.
import UIKit
import Foundation
class TableViewMarketItemsViewCell: UITableViewController {
var fruits = ["Avocado", "Apricot", "Pomegranate", "Quince"]
var PriceArray = ["1000 тг.","4000 тг.","3000 тг.","2000 тг."]
var categoryArray = ["Green category","Maroon category","Red category","Yellow category"]
// MARK: - UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath) as! TableViewCell
let fruitName = fruits[indexPath.row]
cell.productTitle.text = fruitName
cell.productImage.image = UIImage(named: fruitName)
return cell
}
}
Thnx in advance
import UIKit
import Foundation
class TableViewMarketItemsViewCell: UITableViewController {
var fruits = ["Avocado", "Apricot", "Pomegranate", "Quince"]
var PriceArray = ["1000 тг.","4000 тг.","3000 тг.","2000 тг."]
var categoryArray = ["Green category","Maroon category","Red category","Yellow category"]
// MARK: - UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath) as! TableViewCell
let fruitName = fruits[indexPath.row]
cell.productTitle.text = fruitName
cell.productImage.image = UIImage(named: fruitName)
cell.productPrice.text = PriceArray[indexPath.row]
cell.productsubTitle.text = categoryArray[indexPath.row]
return cell
}
}
This helped me.
result in picture below:
img
For inserting data into UITableViewcell use below code:
import UIKit
class ViewController: UIViewController,UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var dataArray:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.dataSource = self
dataArray = NSArray(objects: "a","b","c")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = dataArray.object(at: indexPath.row) as? String
return cell
}
}
tableView is outlet of UItableView.
You can populate an UITableView from an array like below:
(assuming that your array has a list of string values):
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Creating the tableView cell
let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! UITableViewCell
//Assigning values
tableViewCell.lblName?.text = array.object(at: indexPath.row) as? String
return tableViewCell
}
In this way you can show the value from your array to the label in your tableView.