I have the following code to display two tables populated from two different arrays in one view:
#IBOutlet var RFTable: UITableView
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
}
override func viewDidLoad() {
super.viewDidLoad()
self.RFTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return self.RFArray.count;
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell:UITableViewCell = self.RFTable.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel.text = String(self.RFArray[indexPath.row])
return cell
}
#IBOutlet var IMProdTable: UITableView
func tableView2(IMProdTable: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
}
override func viewDidLoad() {
super.viewDidLoad()
self.IMProdTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell2")
}
func tableView2(IMProdTable: UITableView!, numberOfRowsInSection section: Int) -> Int {
return self.IMProdArray.count;
}
func tableView2(IMProdTable: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell2:UITableViewCell = self.IMProdTable.dequeueReusableCellWithIdentifier("cell2") as UITableViewCell
cell2.textLabel.text = String(self.IMProdArray[indexPath.row])
return cell2
}
I got the first table working, and then copied and pasted the text, replacing the array names and tableview names, and have hooked up the delegate and datasource. However Xcode displays 'invalid redeclaration of viewdidload' on the second (pasted) code. If I replace this to 'fund loadView() {' instead of viewdidload the app builds. When I test it though, both tables view exactly the same data which is the data in 'RFArray.' I am VERY new to coding and cannot see what I have done, please help.
#IBOutlet var RFTable: UITableView
#IBOutlet var IMProdTable: UITableView
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
}
override func viewDidLoad() {
super.viewDidLoad()
self.RFTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.IMProdTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell2")
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
if tableView == RFTable {
return self.RFArray.count;
} else {
return self.IMProdArray.count;
}
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
if tableView == RFTable {
var cell:UITableViewCell = self.RFTable.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel.text = String(self.RFArray[indexPath.row])
return cell
} else {
var cell2:UITableViewCell = self.IMProdTable.dequeueReusableCellWithIdentifier("cell2") as UITableViewCell
cell2.textLabel.text = String(self.IMProdArray[indexPath.row])
return cell2
}
}
Just a quick edit. You need to keep the delegate and datasource methods same and check which TableView instance is actually sending the message.
You cannot override the same method twice in a derived class.
First create two DataSource implemented classes
First Data source
class FirstDataSouce: NSObject,UITableViewDataSource,UITableViewDelegate {
var items: [String] = []
override init(){
super.init()
}
func setData(items:[String]){
self.items = items
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RecentTableViewCell") as! RecentTableViewCell
cell.titleLabel.text = items[indexPath.row]
return cell
}
}
Second Data source
class SecondDataSouce: NSObject,UITableViewDataSource,UITableViewDelegate {
var items: [String] = []
override init(){
super.init()
}
func setData(items:[String]){
self.items = items
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RecentTableViewCell") as! RecentTableViewCell
cell.titleLabel.text = items[indexPath.row]
return cell
}
}
Set datasource to tableview in ViewController
class ViewController: UIViewController{
#IBOutlet weak var tableView1: UITableView!
#IBOutlet weak var tableView2: UITableView!
var dataSource1: FirstDataSouce!
var dataSource2: SecondDataSouce!
func prepareTableViews(){
let items1 = [“a”,”b”,”c”]
dataSource1 = FirstDataSouce()
dataSource1.setData(items: items1)
self.tableView1.dataSource = dataSource1
self.tableView1.delegate = dataSource1
self.tableView1.register(SelectorTableViewCell.self,
forCellReuseIdentifier:
"TableViewCell")
self.tableView1.tableFooterView = UIView()
let items2 = [“1”,”2”,”3”]
dataSource2 = SecondDataSouce()
dataSource2.setData(items: items2)
self.recentTableView.dataSource = dataSource2
self.recentTableView.delegate = dataSource2
self.recentTableView.register(RecentTableViewCell.self,
forCellReuseIdentifier:
"TableViewCell")
self.recentTableView.tableFooterView = UIView()
}
}
Also Make Sure To reload each TableView After fetching data to TableviewCell.
e.g
#IBOutlet var RFTable: UITableView
#IBOutlet var IMProdTable: UITableView
override func viewDidLoad() {
super.viewDidLoad()
self.RFTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.IMProdTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell2")
RFTable.reloadData()
IMProdTable.reloadData()
}
Related
I'm getting this error message in my table view controller class
value of uitableviewcell has no member delegate
Here is an image of the error.
Is there anything that should be changed in my code?
import UIKit
class TViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var Tviews: UITableViewCell!
let contacts:[[String]] = [
["Elon Musk", "+1-201-3141-5926"],
["Bill Gates", "+1-202-5358-9793"],
["Tim Cook", "+1-203-2384-6264"],
["Richard Branson", "+1-204-3383-2795"],
["Jeff Bezos", "+1-205-0288-4197"],
["Warren Buffet", "+1-206-1693-9937"],
["The Zuck", "+1-207-5105-8209"],
["Carlos Slim", "+1-208-7494-4592"],
]
override func viewDidLoad() {
super.viewDidLoad()
Tviews.delegate = self
Tviews.datasource = self
// Do any additional setup after loading the view.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViews", for: indexPath)
print("\(#function) --- section = \(indexPath.section), row = \(indexPath.row)")
cell.textLabel?.text = contacts[indexPath.row][0]
return cell
}
You should assign your delegate and data source to your table view instance, and not your table view cell.
In order to do that, create an outlet link with your table view in the TViewController file and then edit your code like this:
import UIKit
class TViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let contacts:[[String]] = [
["Elon Musk", "+1-201-3141-5926"],
["Bill Gates", "+1-202-5358-9793"],
["Tim Cook", "+1-203-2384-6264"],
["Richard Branson", "+1-204-3383-2795"],
["Jeff Bezos", "+1-205-0288-4197"],
["Warren Buffet", "+1-206-1693-9937"],
["The Zuck", "+1-207-5105-8209"],
["Carlos Slim", "+1-208-7494-4592"],
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.datasource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "<your-table-view-cell-id>", for: indexPath) as! YourTableViewCell
cell.textLabel?.text = contacts[indexPath.row][0]
return cell
}
}
I'm stuck with the following, any inputs would be highly appreciated.
My app has a UITableViewController with custom cells. Let's name its UITableView as TABLE VIEW-1. I am using XIB as its custom cell. Inside that xib, there is another UITableView, (TABLE VIEW-2), with another XIB as its custom cell.
My question is, How can I reload cells of (TABLE VIEW-2) from (TABLE VIEW-1) once I get data from an API in (TABLE VIEW-1). I want to use delegate and protocols to do this.
OR, What would be the correct way of performing this and how would I go about it?
Create a reference of TableView1 in the TableView2 ViewController. You can do this by
-- Open the Assistant Editor
-- Right-click and drag from your UI element (i.e. label) to the code file
-- Xcode auto inserts code for you to create the name and connection
Then call tableView2.reloadData(), where tableView2 is the name of the outlet you just created.
Create a reference of the TABLE VIEW-2 in the TABLE VIEW-1 custom cell (TABLE VIEW-1 CELL)
Create a method inside TABLE VIEW-1 CELL to reload its data alone with the TABLE VIEW-2 (Optional but useful to organize your code)
Inside the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell of the TABLE VIEW-1 call reload function
class ViewController: UIViewController {
#IBOutlet weak var mainTable: UITableView!
let sampleData = [
(section: "News", SubSections: [
"Breaking news",
"Current Affairs",
"Local"
]) ]
override func viewDidLoad() {
super.viewDidLoad()
self.mainTable.estimatedRowHeight = 200
self.mainTable.rowHeight = UITableView.automaticDimension
let nib: UINib = UINib(nibName: String(describing: MainCell.self), bundle: Bundle.main)
self.mainTable.register(nib, forCellReuseIdentifier: String(describing: MainCell.self))
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.sampleData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: MainCell = tableView.dequeueReusableCell(withIdentifier: String(describing: MainCell.self), for: indexPath) as! MainCell
let sectionData = self.sampleData[indexPath.row]
cell.setUpData(title: sectionData.section, data: sectionData.SubSections)
return cell
}
}
class MainCell: UITableViewCell {
#IBOutlet weak var sectionTitle: UILabel!
#IBOutlet weak var internalTable: UITableView!
var tableData:[String]?
override func awakeFromNib() {
super.awakeFromNib()
self.internalTable.estimatedRowHeight = 200
self.internalTable.rowHeight = UITableView.automaticDimension
let nib: UINib = UINib(nibName: String(describing: InsideCell.self), bundle: Bundle.main)
self.internalTable.register(nib, forCellReuseIdentifier: String(describing: InsideCell.self))
}
func setUpData(title: String, data:[String]) {
self.sectionTitle.text = title
self.tableData = data
self.internalTable.reloadData()
}
}
extension MainCell: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.tableData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: InsideCell = tableView.dequeueReusableCell(withIdentifier: String(describing: InsideCell.self), for: indexPath) as! InsideCell
if let subSectionData = self.tableData?[indexPath.row] {
cell.subSectionTitle.text = subSectionData
}
return cell
}
}
class InsideCell: UITableViewCell {
#IBOutlet weak var subSectionTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
I have a tableView connected to the array. The array isn't empty but the tableView shows nothing other than lines. Can you help me, please?
var invoicesDictionary = [String:[String]]()
var invoicesSectionTitles = [String]()
var invoices: [String] = ["JV1", "R1", "JV2"]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
for invoice in invoices {
let invoiceKey = String(invoice.prefix(1))
if var invoiceValues = self.invoicesDictionary[invoiceKey] {
invoiceValues.append(invoice)
self.invoicesDictionary[invoiceKey] = invoiceValues
} else {
self.invoicesDictionary[invoiceKey] = [invoice]
}
}
invoicesSectionTitles = [String](invoicesDictionary.keys)
invoicesSectionTitles = invoicesSectionTitles.sorted(by: { $0 < $1 })
tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return invoicesSectionTitles.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let invoiceKey = invoicesSectionTitles[section]
if let invoiceValues = invoicesDictionary[invoiceKey] {
return invoiceValues.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let invoiceKey = invoicesSectionTitles[indexPath.section]
if let invoiceValues = invoicesDictionary[invoiceKey] {
cell.textLabel?.text = invoiceValues[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return invoicesSectionTitles[section]
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return invoicesSectionTitles
}
I printed out the array which is without a doubt not empty. I tried this code on an another project and it just worked.
You have to put this in viewDidLoad :
tableView.delegate = self
tableView.dataSource = self
You have to tell the View controller that it's the delegate or assigned VC for the table View functionality by passing the following lines inside viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
I have two view controller with tableviewcell and in both of them I can add items.
What I want to implement is that when I add items in the first tableviewcell lets say I add (item one , item two) and press on (item one).
I want to sugue to the second tableviewcell and add data.
BUT I want the data in the second tableviewcell to save separately,
that means, now if I press on (item one) I should see the data that I added
but if I press on (item two) it should be empty and I can add data later.
I have saved the data for the two tableviewcell in coredata.
I don't use segues or coredata in this solution, but the solution will fix what you need to some extent at least.
class vc1: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
let options: [Int] = [1,2]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return options.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = vc2()
//Not sure where to put the setup to be honest
//option 1:
vc.setupTableView(forCell: indexPath.item)
present(vc, animated: true) {
//option 2:
vc.setupTableView(forCell: indexPath.item)
}
}
}
class vc2: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
var selectedCell: Int!
//Having an nested array in an array will solve this custom "page" you are looking for
let results: [[String]] = [["test1", "test2"], ["test3", "test4"]]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func setupTableView(forCell cell: Int) {
selectedCell = cell
tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results[selectedCell].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel = results[selectedCell][indexPath.item]
return UITableViewCell()
}
}
I am having a weird issue where for some reason my UITableView is not being reloading after performing a search. The console prints out the correctly filtered data, but the table simply doesn't change. I have never encountered this issue, so I first attempted the solutions which naturally came to mind:
Tried tableView.reloadData() in the Main Queue
Quit Xcode, clean build, reinstall
Cleared out the derived data dir
I have found several similar issue in SO, but all of the solutions I've seen are things I've tried, mainly reloading tableview in main queue.
Hoping maybe I just simply have an issue in my code or something I'm missing.
I am running Xcode 8.3.3
import UIKit
class CategoriesViewController: UIViewController {
var isFiltering = false
var location = Location()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var categoriesSearchResults = [Category]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.allowsSelection = true
tableView.keyboardDismissMode = .onDrag
let nib = UINib(nibName: "CategoryTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier:"CategoryTableViewCell");
searchBar.returnKeyType = UIReturnKeyType.done
searchBar.autocapitalizationType = .none
searchBar.delegate = self
}
extension CategoriesViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("HI")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering {
return self.categoriesSearchResults.count
}
return self.location.categories.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
}
return cell
}
}
extension CategoriesViewController : UISearchBarDelegate {
func searchBarIsEmpty() -> Bool{
return self.searchBar.text?.isEmpty ?? true
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.isFiltering = true
self.categoriesSearchResults.removeAll()
tableView.reloadData()
self.view.endEditing(true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBarIsEmpty() {
self.view.endEditing(true)
self.isFiltering = false
} else {
self.isFiltering = true
self.categoriesSearchResults = self.location.categories.filter({ (category: Category) -> Bool in
return category.name.lowercased().contains(searchText.lowercased())
})
}
tableView.reloadData()
}
}
and my custom table view cell:
import UIKit
class CategoryTableViewCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var status: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func prepareForReuse() {
super.prepareForReuse()
self.name.text = ""
self.status.text = ""
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Thank you in advance.
EDIT: Might also be worth mentioning, when I am actively searching, the function tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) is not called??
The scope of if let nests in its scope. In your code you are always returning let cell = UITableViewCell(). Try returning it inside the if let :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
/// RETURN CELL HERE
return cell
}
return cell
}