I’m trying to put a tableView inside a collectionView sectionHeader. I tried adding a tableView to the header in storyboard and then setting its class to tableViewController.swift but that didn’t work.
(I’m using swift)
After trying a bit i did manage to get it working properly.
First i created a header as normal, then created an IBOutlet of the tableView.
Then I simply setup the header file like a tableViewController is setup, connected to the dataSource and delegate in awakeFromNib and done.
class HomeHeader: UICollectionReusableView, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func awakeFromNib() {
tableView.delegate = self
tableView.dataSource = self
//tableView.backgroundColor = UIColor.clear
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1 //number of sections
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5 //number of cells
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = "test"
// cell.backgroundColor = UIColor.clear
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
Related
I am asked to do optimise my swift code especially when it comes to UI Delegate methods.
Scenario: I have UITableView in five UIViewControllers, in each view controller I am using UITableView delegate methods due to which my code is repeating. So how can I optimise this thing?
Below is the structure of code: You can see delegate method code is repeating
class FirstViewController: UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var userArray = [UserModel]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
// register cell according to model (Dynamic Cells)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell01", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
class SecondViewController: UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var productArray = [ProductModel]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
// register cell according to model (Dynamic Cells)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell01", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
I have a tableView displaying [Double]. Very Simple. But I also wanna display the average of the onscreen numbers on every row, and the difference between this number and the average.
Because I need to re-calculated the average every time a new row appears, I'm thinking about accessing tableView.visibleCells in cellForRowAt: indexPath method, and then update the average of this row and every other rows on screen, because the average of onscreen rows should be the same for all the onscreen rows.
But then I got this error message [Assert] Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed. Make a symbolic breakpoint at UITableViewAlertForVisibleCellsAccessDuringUpdate to catch this in the debugger and see what caused this to occur. Perhaps you are trying to ask the table view for the visible cells from inside a table view callback about a specific row?
While this is loud and clear, I'm wondering what is the correct way or workaround for this?
Code is very simple
class ViewController: UIViewController {
var data:[Double] = [13,32,43,56,89,42,26,17,63,41,73,54,26,87,64,33,26,51,99,85,57,43,30,33,20]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "default")!
cell.textLabel?.text = "\(data[indexPath.row])"
print(tableView.visibleCells.count) // THIS LINE PRODUCE ERROR
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 64
}
}
What I have tried:
I've tried didEndDisplaying and willDisplay, when I added print(tableView.visibleCells.count) to either of them, same error message was given back.
Answer:
You can use UITableView's delegate functions to calculate this.
tableView(_:willDisplay:forRowAt:) is called every time before cell becomes visible, so you can recalculate your average value at this moment. Also, there is tableView(_:didEndDisplaying:forRowAt:) which fires when cell goes off display and also can be used to recalculate.
Documentation:
tableView(_:willDisplay:forRowAt:)
tableView(_:didEndDisplaying:forRowAt:)
UPD:
For calculation use tableView.indexPathsForVisibleItems
Example:
import UIKit
class ViewController: UIViewController {
var data:[Double] = [13,32,43,56,89,42,26,17,63,41,73,54,26,87,64,33,26,51,99,85,57,43,30,33,20]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
self.tableView.dataSource = self
self.tableView.delegate = self
self.tableView.reloadData()
}
private func calculate() {
let count = tableView.indexPathsForVisibleRows?.count
let sum = tableView.indexPathsForVisibleRows?
.map { data[$0.row] }
.reduce(0) { $0 + $1 }
if let count = count, let sum = sum {
print(sum / Double(count))
}
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "default")!
cell.textLabel?.text = "\(data[indexPath.row])"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 64
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
calculate()
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
calculate()
}
}
I wanted to give a go at swift, and looked at several tutorials. I tried to implement a TableView.
Here is my code :
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var items: [String] = ["lol1", "lol2", "lol3"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1;
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
print("You selected cell #\(items[indexPath.row])!")
}
}
MY IBOutlet is connect to the tableview I inserted in the storyboard.
When I run it, I have a TableView, but it's missing contents.
From what I gathered through some (more or less outdated) tutorials, I shouldn't have anything more to do, what am I missing ?
Where are you set dataSource and Deleagte methods of TableView?
use this code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tableView.dataSource = self
self.tableView.delegate = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
2 possible reasons:
If the cell is designed as prototype cell you must not register the cell.
dataSource and delegate of the table view must be connected to the controller in Interface Builder or set in code.
I'm updating an app of mine, and I have used this method in other areas of the app and it works, but for some reason, it's not working on a tableView.
The tableView is inside of a ViewController (CurrencyViewController)
#IBOutlet weak var tableView: UITableView!
tableView.dataSource = self
extension CurrencyViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currencies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "currencyCell")! as! CurrencyTableViewCell
cell.name.text = currencies[indexPath.row].currencyName
cell.name.textColor = Styles.whiteColor()
cell.symbol.text = currencies[indexPath.row].currencyCode
cell.symbol.textColor = Styles.whiteColor()
cell.backgroundColor = Styles.mainColor();
return cell
}
}
The tableView itself works, it's just not updating the height of the row.
Did something change with the update of Swift?
You don't seem to have conformed to the UITableViewDelegate ?
extension CurrencyViewController: UITableViewDataSource, UITableViewDelegate
If dataSource (and delegate) is connected in IB delete
tableView.dataSource = self
You must also adopt UITableViewDelegate in the extension, connecting the delegate is not sufficient
extension CurrencyViewController: UITableViewDataSource, UITableViewDelegate {
I am trying to display a textfield on a tableview using a custom cell. I think I have set up the delegation protocol properly, but when loaded, the tableview doesn't show the textfield. I have added a textfield into the customcell, set the class to CustomCell, and changed the identifier to "Cell", but I am not sure what else I am missing.
view controller with tableview:
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Hello")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
cell.cellDelegate = self
cell.contentView.bringSubview(toFront: cell.textField)
cell.textField.delegate = self as? UITextFieldDelegate
cell.textField.text = "Test"
return cell
}
func didPressTextField(indexPath: IndexPath) {
print("textfield was tapped")
}
custom cell VC:
protocol CustomCellDelegate : class {
func didPressTextField(indexPath: IndexPath)
}
class CustomCell: UITableViewCell {
weak var cellDelegate: CustomCellDelegate?
var indexPath: IndexPath!
override func awakeFromNib() {
super.awakeFromNib()
self.cellDelegate = nil
// Initialization code
}
#IBOutlet weak var textField: UITextField!
#IBAction func textFieldWasTapped(_ sender: UITextField) {
self.cellDelegate?.didPressTextField(indexPath: indexPath)
}
Your data source is empty.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// data is not containing any value
return data.count
}
Check data.count it should have some data and also if that is custom cell with XIB then you need to register cell in view didload
self.tableView.register(UINib(nibName: "Your Cell XIB name", bundle: nil),
forCellWithReuseIdentifier: "Cell")
Check your data.count. it must return value greater than 0 otherwise your tableView is showing with 0 rows and nothing is display in tableView.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// debug at this point check what is value of data.count its must be greater than 0
return data.count
}