UItableView Section Header View with Xib Error - Swift - swift

I try to implement Section Header with Xib File. I create a Xib View and attend UITableViewHeaderFooterView to this view . When I run the App , it gives me error without any description. Where is the problem ?
Thanks in advance.
tableView.register(UINib(nibName: "EventViewCell", bundle: nil), forCellReuseIdentifier: "EventViewCell")
tableView.register(UINib(nibName: "EventCellSectionHeader", bundle: nil), forHeaderFooterViewReuseIdentifier: "EventCellSectionHeader")
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: "EventCellSectionHeader") as! EventCellSectionHeader
cell.headerName.text = "aa"
return cell
}
class EventCellSectionHeader: UITableViewHeaderFooterView {
#IBOutlet var headerName: UILabel!
}
libc++abi.dylib: terminating with uncaught exception of type NSException

Xcode 10 SWIFT 4
implement your viewForHeaderInSection as below:
//EventCellHeader is the name of your xib file. (EventCellHeader.xib)
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = Bundle.main.loadNibNamed("EventCellHeader", owner: self, options: nil)?.last as! EventCellSectionHeader
header.headerName.text = "aa"
return header
}
I tested it: (if you need more help let me know to send you the whole project)

Related

unable to dequeue a cell with identifier cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

I am new to SWIFT and trying to show some data into table view controller but when I press the button it shows the above error. Please correct me
import UIKit
var selectedPlace : Place!
class ShowPlaceTableTableViewController: UITableViewController {
var places : [Place]!
override func viewDidLoad()
{
super.viewDidLoad()
places = readPlaces()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return places.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PlaceTableViewCell
cell.countryLabel.text = places[indexPath.row].country
cell.placeImageView.image = places[indexPath.row].picture
return cell
}
func readPlaces() -> [Place]
{
if UserDefaults.standard.object(forKey: "places") != nil
{
var data = UserDefaults.standard.object(forKey: "places") as! Data
let places = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [Place]
return places
}else
{
return [Place]()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedPlace = places[indexPath.row]
performSegue(withIdentifier: "detailSegue", sender: self)
}
}
Is your PlaceTableViewCell inside it's own xib separately OR is it inside the storyboard itself? You must register either a cell class or a nib before you try to dequeue the cell from tableView.
If it's inside the storyboard, then you can register the subclass to work with it.
tableView.register(PlaceTableViewCell.self, forCellReuseIdentifier: "PlaceTableViewCell")
If it's inside it's own xib separately, then you can register the UINib to work with it.
tableView.register(UINib(nibName: "PlaceTableViewCell", bundle: nil), forCellReuseIdentifier: "PlaceTableViewCell")
These need to be called once only, you can place these calls inside viewDidLoad().
Now you can dequeue it like following -
let cell = tableView.dequeueReusableCell(withIdentifier: "PlaceTableViewCell") as! PlaceTableViewCell
Note : The reuseIdentifier must be same in following places -
storyboard (or xib)
at the time of registration tableView.register...
at the time of dequeue tableView.dequeue...

Swift UITableview Reload 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
}
}

Navigate from a ViewController to an another on didSelectRowAt programmatically

I have a UIViewController that contains a custom UITableView. The table has a custom UITableViewCell too.
How to navigate from the first ViewController to an another when you select/click one of the rows?
Note
I have not used StoryBoard.
Update
This my code. Each one of the classes are external file. Let me know, if you need more code.
class TestViewController: UIViewController, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(testTableView)
}
let testTableView: TestTableView = {
let table = TestTableView()
table.register(TestTableViewCell.self, forCellReuseIdentifier: TestTableViewCell.identifier)
return table
}()
}
class TestTableView: UITableView, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TestTableViewCell.identifier, for: indexPath)
return cell
}
}
class TestTableViewCell: UITableViewCell {
static let identifier = "testCell"
}
Here is a complete answer:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newViewController = NewViewController()
self.navigationController?.pushViewController(newViewController, animated: true)
}
In UIKit in order to programmatically navigate from TableCell you can do it without storyboard.
You have two ways to view next viewController
If you want to present .......
animating from bottom to top
(one thing to remember) you can not present new view without dismissing previous presented screen, otherwise app crash due to conflict of presented screen
yourTableView.deselectRow(at: indexPath, animated: true)//used for single Tap
let vC = YourViewController (nibName: "" , bundle : nil)
vC.modalPresentationStyle = .fullScreen //this line is optional for fullscreen
self.present(vC, animated: true , completion: nil)
Or if you want to View your viewController normally (2 is batter) ....
animate from right to left
yourTableView.deselectRow(at: indexPath, animated: true)
let vC = YourViewController()
self.navigationController?.pushViewController(vC, animated: true)
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = yourCustomVCName (nibName: "yourCustomVC nibName" , bundle : nil)
self.present(vc, animated: true , completion: nil)
}

dequeue reusable cell always crashes

in this code i add the programatic VC:
#IBAction func addPerson(_ sender: UIBarButtonItem) {
let controller = CNContactPickerViewController()
controller.delegate = self
navigationController?.present(controller, animated: true, completion: nil)
}
here i use to go on another VC when i click on a contact (to show info into cells and then i want to make a checkbox for phones/emails to show back in my first VC)
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
let vc = EditContactViewController()
self.navigationController?.pushViewController(vc, animated: true)
i created a class for the next cell and i set up identifier as cell in storyboard
when i do this in tableView cellForRowAtIndexPath
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? ConfigCell
return cell!
this gives me:
fatal error: unexpectedly found nil while unwrapping an Optional value
i also tried withIdentifier,forIndexPath and it says:
2016-11-12 01:35:28.626 iEvents3[2637:47714] *** Terminating app due
to uncaught exception 'NSInternalInconsistencyException', reason:
'unable to dequeue a cell with identifier cell - must register a nib
or a class for the identifier or connect a prototype cell in a
storyboard'
i deleted reuse identifier and put it back again , cleaned the application, restart, everything.
Thank You for your time!
There can be several reason for this:
If you have your UITableViewCell in controller itself, then check the reuse identifier whether it is set to "cell"
If you have a separate .xib for your UITableViewCell, then
a) Register the .nib of cell with your table view in viewDidLoad() of your controller
self.tableView.register(UINib(nibName:"CustomTableViewCell"), forCellWithReuseIdentifier: "cell")
Register the .nib only when you are sure the outlet of table view is set. Otherwise, if the outlet if table view is still nil, it won't register the .nib of your cell.
b) Check whether the reuse identifier is set to "cell"
Make sure there is no '!' sign in interface outlet connections
Even if you don't have a xib for the cell, you may need to register it:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
Do you have that cell as a xib? Did you add your cell to the table view? Try this if this is the case
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
self.tableView.register(UINib(nibName: "ConfigCell",bundle: nil), forCellReuseIdentifier: "cell")
}
When cell expand it crash application
func tableView(_ tableView: SLExpandableTableView!, willExpandSection section: UInt, animated: Bool)
{
}
func tableView(_ tableView: SLExpandableTableView!, didExpandSection section: UInt, animated: Bool)
{
let indexPath = IndexPath(row: 0, section: Int(section))
let cell: SLExpandableHeaderCell = (tableView.cellForRow(at: indexPath) as! SLExpandableHeaderCell)
cell.empProfImage?.image = UIImage(named: "upArrowGrey.png")
// let imgCategorySymbol: UIImageView = (cell.viewWithTag(5030) as! UIImageView)
// imgCategorySymbol.image = UIImage(named: "upArrowGrey.png")
for i in 0..<arrCategoriesServices.count
{
if !selectedSectionIndex.contains("\(i)") && i != Int(section) {
tableView.collapseSection(i, animated: true)
}
}
}
func tableView(_ tableView: SLExpandableTableView!, willCollapseSection section: UInt, animated: Bool) {
let indexPath = IndexPath(row: 0, section: Int(section))
let cell: SLExpandableHeaderCell = (tblExpandableView.cellForRow(at: indexPath) as! SLExpandableHeaderCell)
cell.empProfImage?.image = UIImage(named: "downArrowGrey.png")
// let imgCategorysymbol: UIImageView? = (cell.viewWithTag(5030) as! UIImageView)
// imgCategorysymbol?.image = UIImage(named: "downArrowGrey.png")
}
func tableView(_ tableView: SLExpandableTableView, canChangeSection section: Int) -> Bool {
if collapsingSection != section {
return true
}
else {
return false
}
}
func tableView(_ tableView: SLExpandableTableView!, didCollapseSection section: UInt, animated: Bool) {
}
func tableView(_ tableView: SLExpandableTableView, canExpandSection section: Int) -> Bool
{
return true
}
func tableView(_ tableView: SLExpandableTableView!, needsToDownloadDataForExpandableSection section: Int) -> Bool
{
return false
}
func tableView(_ tableView: SLExpandableTableView!, expandingCellForSection section: Int) -> UITableViewCell
{
var cell: SLExpandableHeaderCell!
if cell == nil
{
cell = tblExpandableView.dequeueReusableCell(withIdentifier: headerCell) as! SLExpandableHeaderCell
}
let label = UILabel()
label.frame = CGRect(x: CGFloat(10), y: CGFloat(10), width: CGFloat(100), height: CGFloat(25))
cell.addSubview(label)
cell.empProfImage?.image = UIImage(named: "downArrowGrey.png")
cell?.selectionStyle = .none
let cat: CategoryModel = (arrCategory[section] as! CategoryModel)
label.text = cat.categoryName
print("Expanding table for categoty : \(cat.categoryName)")
// cell.textLabel?.frame = frame
// cell?.textLabel?.text = cat.categoryName
// Util.setCategoryDetailFontColorAndSize(label: (cell?.textLabel!)!, labelText: cat.categoryName)
Util.setCategoryDetailFontColorAndSize(label: label, labelText: cat.categoryName)
cell?.textLabel?.backgroundColor = UIColor.clear
return cell!
}
public func tableView(_ tableView: SLExpandableTableView!, downloadDataForExpandableSection section: Int)
{
}
In my case it was a silly mistake, just a misprint in the name of the .xib, but it took me too much time to find it because the name was very long and difficult to see the mistake, and so I was searching for other causes.
It seems so obvious now.. but shit happens :)
I hope save your time if it's your case.
For me, the TableView Cell was set to Static content instead of Dynamic since I want it to generate X numbers of cells based on my collection. A good clue was that I saw a weird Header Text with a blue cube above my Table View Cell in the hierarchy overview panel in Xcode.
Here's a visual where to set the Cells to Dynamic.

Custom Xib Cell with Tableview isn't working

I'm creating a slide out menu with xib files using the following tutorial:
https://www.raywenderlich.com/78568/create-slide-out-navigation-panel-swift
Now I'm at the point to make the xib tableview view with the custom tableview cell. Reading several questions on stackoverflow I came to the following code
override func viewDidLoad() {
super.viewDidLoad()
var nib = UINib(nibName: "MenuCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "menucell")
tableView.reloadData()
print("count: \(animals.count)")
}
and the actual cell
extension SidePanelViewController: UITableViewDataSource {
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return animals.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:MenuTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("menucell", forIndexPath: indexPath) as! MenuTableViewCell
cell.configureCell(animals[indexPath.row])
return cell
}
But the tableview is not showing the custom tableview cells with the title. Can anyone help me with this problem?
Probably you have forgot to set this parameters:
tableView.delegate = self
tableView.datasource = self
As explained in comments:
Correct your class declaration like this for example:
class myClass: SidePanelViewController , UITableViewDataSource, UITableViewDelegate { .. }
Try to cross check the following because you have added the xib explicitly in your bundle as your class name and xib name differs
Cross check 1
You have mentioned you custom class MenuTableViewCell in Identity Inspector window
Cross check 2
You have mention the cell identifier in the Attributes Inspector window as