Multiplied value in tableView Swift - ios

I want to generate cell dynamically according to the number of rows in a Dictionary. On view load, the dictionary is null and is binded on the road.
The dictionary is well binded with three key-values, but when I want to create cell according to dictionary values and keys always creates three rows with the last item in the dictionary.
I can't figure it out why.
This is my code:
var peripherals = [String:String]()
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(peripherals.count)
return peripherals.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)
for (peripheralDeviceUUID,peripheralDeviceName) in peripherals {
cell.textLabel?.text = "\(indexPath) \(peripheralDeviceName) : \(peripheralDeviceUUID)"
}
return cell
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section)"
}

Firt make arrays of keys and values from your dictionary.
let dict = ["a": "first", "b": "second", "c": "third"]
let arrayKeys = Array(dict.keys)
let arrayValues = Array(dict.values)
then use those arrays in cellForRow:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)
cell.textLabel?.text = "\(indexPath.row) \(arrayValues[indexPath.row]) : \(arrayKeys[indexPath.row])"
return cell
}

Related

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.

How to separate cells into sections with custom header?

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
}

multiple cell in tableview

I am working on an ios project which uses tableview. I could populate tableviews properly but now I want two cells in a tableview.
This is a fixed cell one which I could put datepicker into
This should be populated with data maybe from a storage or hard coded.
this means I want the first cell to be fixed because it contains the datepicker alone.
this is my code so far for implementing the (2) requirement which means I am only able to implement one cell.
let animals: [String] = ["Horse", "Cow", "Camel", "Sheep", "Goat"]
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return animals.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = animals[indexPath.row]
return cell
}
any help would be appriciated. thanks
let animals: [String] = ["Horse", "Cow", "Camel", "Sheep", "Goat"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}else{
return animals.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "CELL_IDENTIFIER_FOR_DATEPICKER_CELL", for: indexPath)
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: "CELL_IDENTIFIER_FOR_DEFAULT_CELL", for: indexPath
cell.textLabel?.text = animals[indexPath.row]
return cell
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
You can make 2 sections for this::
let animals: [String] = ["Horse", "Cow", "Camel", "Sheep", "Goat"]
override func numberOfSections(in tableView: UITableView) -> Int {
return 2 // one for cell 1, and other for 2nd types
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 { return 1 } // 1 for datePicker
else { return animals.count } // requirement 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if indexPath.section == 0 {
cell.textLabel?.isHidden= true
var datePicker = ...
// create date Picker and cell.contentView.addSubview(datePicker)
} else {
cell.textLabel?.text = animals[indexPath.row]
}
return cell
}

How to perform a dynamic creation of sections and cells to a UITableView in SWIFT 3

I've got a sample code but rows per section won't show, since numberOfRowsInSection doesn't exist in SWIFT 3 anymore.
I currently have the ff code:
let section = ["pizza", "deep dish pizza", "calzone"]
let items = [["Margarita", "BBQ Chicken", "Pepperoni"], ["sausage", "meat lovers", "veggie lovers"], ["sausage", "chicken pesto", "prawns", "mushrooms"]]
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return self.section[section]
}
override func numberOfSections(in tableView: UITableView) -> Int {
return self.section.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
// Configure the cell...
cell.textLabel?.text = self.items[indexPath.section][indexPath.row]
return cell
}
Result:
Can someone show the correct code for updated swift 3? Thanks!
For your information numberOfRowsInsection exists in swift3, see below
override func numberOfSections(in tableView: UITableView) -> Int {
return section.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items[section].count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell?.textLabel?.text = items[indexPath.section][indexPath.row]
return cell!
}
Thanks:)

fatal error: Index out of range when using UITableView with multiple sections

I am trying to delete items from an array using a UITableView, however the UITableView has multiple sections and I keep getting the following error when deleting the cell
fatal error: Index out of range
For:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
// Delete the row from the data source
if editingStyle == UITableViewCellEditingStyle.delete {
if let table = self.table {
self.sectionItems.remove(at: [(indexPath as NSIndexPath).section][(indexPath as NSIndexPath).row])
table.deleteRows(at: [indexPath], with: UITableViewRowAnimation.left )
}
}
}
Here's how I am populating the UITableView
let sections = ["One", "Two", "Three", "Four"]
var sectionItems = [ [String](), [String](), [String](), [String]() ]
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (self.sectionItems[section] as AnyObject).count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
cell.textLabel!.text = self.sectionItems[(indexPath as NSIndexPath).section][(indexPath as NSIndexPath).row]
return cell
}
Does anybody know where I am going wrong ?
I tried changing
table.deleteRows(at: [indexPath], with: UITableViewRowAnimation.left )
to
table.deleteRows(at: [(indexPath as NSIndexPath).section][(indexPath as NSIndexPath)]
But I get the error:
Cannot subscript a value of type '[Int]' with an index of type
'NSIndexPath'
You are calling remove on the wrong array. You are calling it on your sectionItems array, not the array that is contained in the sectionItems array.
You need to use the indexPath.section to retrieve the appropriate array first, then call remove:
self.sectionItems[indexPath.section].remove(at:indexPath.row)

Resources