I have 2 xib files: the custom UIView and the Custom Cell xib.
I also have a Custom Cell class that only contains a UILabel.
The names are all correct.
The delegates of the UITableView are connected to the view.
I need to add a UITableView to a UIView. From the tutorials I've read this is how to add it. But for some reason this does not work I get 2 types of errors with this code that say that I need to register the cell nib or that It finds nil when unwrapping an optional. What am I doing wrong? Please help!
private let myArray: NSArray = ["First","Second","Third"]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Num: \(indexPath.row)")
print("Value: \(myArray[indexPath.row])")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
cell.textLabel!.text = "\(myArray[indexPath.row])"
return cell
}
#IBOutlet var contentView: UIView!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var HelperLabel: UILabel!
override init(frame: CGRect){
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
let nib = UINib(nibName: "MyCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "MyCell")
tableView.dataSource = self
tableView.delegate = self
self.addSubview(tableView)
Here is the complete Code for your Problem
Code For CustomCell Class : Take Custom Xib For Cell
import UIKit
class CustomCell: UITableViewCell {
#IBOutlet weak var myLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Code For CustomView Class: Take Custom Xib For View
import UIKit
class CustomView: UIView {
var tableData: [String] = ["First","Second","Third"]
#IBOutlet weak var myTableView: UITableView!
class func instanceFromNib() -> UIView {
return UINib(nibName: "CustomView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
static func nibInstance() -> CustomView? {
let customView = UINib(nibName: "CustomView", bundle: nil).instantiate(withOwner: nil, options: nil).first as? CustomView
return customView
}
func baseInit() {
self.myTableView.delegate = self
self.myTableView.dataSource = self
self.myTableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
}
}
extension CustomView : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.myLabel.text = tableData[indexPath.row]
return cell
}
}
Note : Set the Xib CustomClass to UIView Class whatever you want to take in my case it is "CustomView"
Controller Code :
class CustomViewController: UIViewController {
var customView : CustomView?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.asyncAfter(deadline: DispatchTime(uptimeNanoseconds: UInt64(0.5))) {
self.loadViewCustom()
}
}
func loadViewCustom() {
self.customView = CustomView.nibInstance()
self.customView?.frame = self.view.frame
self.customView?.baseInit()
self.view.addSubview(self.customView!)
self.customView?.myTableView.reloadData()
}
}
tableView is IBOutlet in xib file? why you need addSubView?
Related
The above one is my inner cell. I want to load this cell inside the below cell. The number of inner cell is dynamic.
The above one is my main cell. The red colored section is a UIView. I want to add numbers of innerCell dynamically into the UIView. I tried the below code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let mainCell = tableView.dequeueReusableCell(withIdentifier: "FlightCellMain", for: indexPath) as? FlightCellMain
let innerCell = tableView.dequeueReusableCell(withIdentifier: "FlightCell", for: indexPath) as? FlightCell
mainCell?.flightCellView.addSubview(innerCell!)
mainCell?.backgroundColor = .clear
innerCell?.backgroundColor = .clear
// innerCell?.innerCellWidthConst.constant = (mainCell?.mainView.frame.width)!
self.showStopsView(2, self.airportlist, (innerCell?.leftRound)!, (innerCell?.rightRound)!, (innerCell?.centerLine)!, (innerCell?.routeView)!)
mainCell?.flightCellViewHieghtConst.constant = (mainCell?.flightCellViewHieghtConst.constant)! + 125
innerCell?.layoutIfNeeded()
mainCell?.layoutIfNeeded()
return mainCell!
}
But the result is getting like this. I provided autolayout. When I run the two cells individually it fits its content.. Whats wrong am I doing ?
The above picture is the model that I'm trying to achieve. Where the number of flights details is dynamic.
Step 1: Create a FlightDisplayView(UIView).
import UIKit
class FlightDisplayView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit (){
let xibs = Bundle.main.loadNibNamed("FlightDisplayView", owner: self, options: nil)
let view = xibs?.first as! UIView
view.frame = self.bounds;
self.addSubview(view)
}
}
Step 2: Create a FlightDisplayCell(UITableViewCell).
import UIKit
class FlightViewCell: UITableViewCell {
#IBOutlet weak var innerCellView:FlightDisplayView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Step 3: Create a mainCell(UITableViewCell).
import UIKit
class mainCell: UITableViewCell {
#IBOutlet weak var table: UITableView!
#IBOutlet var heightConstraintForFlightTableView : NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
table.delegate = self
table.dataSource = self
table.estimatedRowHeight = 100.0
table.rowHeight = UITableViewAutomaticDimension
table.register(UINib.init(nibName: "FlightViewCell", bundle: nil), forCellReuseIdentifier: "FlightViewCell")
heightConstraintForFlightTableView.constant = 0.0
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setInformation(_ numberOFFlight : CGFloat, _ information : NSDictionary) {
heightConstraintForFlightTableView.constant = numberOFFlight * 155.0
// 155 is fixed flight cell height
table.reloadData()
}
}
extension mainCell:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FlightViewCell")
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension;
}
}
Step 4: Use mainCell into your controller. (3 cell information added as a inner cell)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mainCell") as? mainCell
let information:NSDictionary = [:]
cell?.setInformation(3, information)
return cell!
}
I am making a view controller with tableView for presenting individual news cards. I want to load cells once and for all (without reusing it as usual). So I do this:
tableView.register(UINib(nibName: "RatingNewsCell", bundle: nil), forCellReuseIdentifier: "RatingNewsCell")
tableView.register(UINib(nibName: "PromoNewsCell", bundle: nil), forCellReuseIdentifier: "PromoNewsCell")
var cells = [UITableViewCell]()
let rating = RatingNewsCell()
rating.delegate = self
cells.append(rating)
etc...
self.items = cells
Cells are loaded like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return items[indexPath.section]
}
Cell code looks like this:
class RatingNewsCell: UITableViewCell
{
var delegate: RatingNewsCellDelegate?
#IBOutlet weak var shopNameLabel: UILabel!
#IBOutlet weak var bouquetImageView: RoundImageView!
#IBOutlet weak var floristImageView: RoundImageView!
#IBOutlet weak var ratingControl: RatingPicker!
override init(style: UITableViewCellStyle, reuseIdentifier: String?)
{
super.init(style: style, reuseIdentifier: "RatingNewsCell")
}
required init?(coder decoder: NSCoder)
{
super.init(coder: decoder)
}
override func awakeFromNib()
{
super.awakeFromNib()
ratingControl.setSelected(newIndex: 0)
}
}
In the result I've got a table view, but cell just appears blank:
Any ideas?
I suggest to refactor your code to use tableView's datasource method though you are only using static cells.
enum Section: Int {
case RatingNews
case PromoNews
static var count: Int { return Section.PromoNews.rawValue + 1 }
}
func numberOfSections(in tableView: UITableView) -> Int {
return Section.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let section = Section(rawValue: indexPath.section)!
switch section {
case .PromoNews:
let cell = tableView.dequeueReusableCell(withIdentifier: "RatingNewsCell", for: indexPath) as! RatingNewsCell
return cell
case .RatingNews:
let cell = tableView.dequeueReusableCell(withIdentifier: "PromoNewsCell", for: indexPath) as! PromoNewsCell
return cell
}
}
You need to call
tableView.delegate = self
and
tableView.dataSource = self
I want to add a UICollectionView inside a table view cell.For this purpose, i have created below files.
CollectionCell:
class CollectionCell: UICollectionViewCell {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var imgCell: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
I have also created a CollectionCell.xib
CollectionView.swift
class CollectionView: UIView {
#IBOutlet weak var collectionview: UICollectionView!
var arrItems:[String] = []
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
func configureCollectionView()
{
collectionview.register(CollectionCell.self, forCellWithReuseIdentifier: "CollectionCell")
collectionview.delegate = self
collectionview.dataSource = self
}
func setCollectionViewDatasource(arrItems:[String])
{
self.arrItems = arrItems
self.collectionview.reloadData()
}
static func initiateView()->CollectionView
{
let nib = UINib(nibName: "CollectionView", bundle: nil)
let view = nib.instantiate(withOwner: nil, options: nil)[0] as! CollectionView
return view
}
}
extension CollectionView:UICollectionViewDelegate
{
}
extension CollectionView:UICollectionViewDataSource
{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:CollectionCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
cell.lblName.text = arrItems[indexPath.row]
return cell
}
}
I have also created CollectionView.xib
Now as i want to add a collectionview inside a tableview cell for that purpose i have created a cutom tableview cell class as CustomTableCell
class CustomTableCell: UITableViewCell {
var view = CollectionView()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
print("ceonstatructir init")
// insitate a nib
view = CollectionView.initiateView()
view.configureCollectionView()
contentView.addSubview(view)
view.setCollectionViewDatasource(arrItems: ["firest","second","thierd"])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setDataSource(arrItems:[String])
{
//view.setCollectionViewDatasource(arrItems: arrItems)
}
}
Now i have created a mainViewController to show the data on tableview so i have crteated viewcontroller.swift
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
let sectionArray = ["First","Second","Third","Fourth","Fifth"]
let collectionArray = [["First","Second","Third"],["First","Second","Third"],["First","Second","Third"],["First","Second","Third"],["First","Second","Third"]]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableview.register(CustomTableCell.self, forCellReuseIdentifier: "TableCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return sectionArray.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionArray[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:CustomTableCell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! CustomTableCell
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell:CustomTableCell = cell as! CustomTableCell
let dataSource = collectionArray[indexPath.section]
cell.setDataSource(arrItems:dataSource)
}
}
Now i am trying to send datasource to my collectionview when tableviewcell is just created.But i am getting crash in cellForItemAtIndexPath in collectionview.I am getting cell as nil in cellForItemAyIndexPath.Please tell me what is the issue with it.
In Collectionview.swift change this function
func configureCollectionView()
{
let nib = UINib(nibName: "CollectionCell", bundle: nil)
collectionview.register(nib, forCellWithReuseIdentifier: "cell")
collectionview.delegate = self
collectionview.dataSource = self
}
In cellforItemat change this line
let cell:CollectionCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
to
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionCell
import UIKit
class NewOrdersViewControllers: UIViewController,UITableViewDelegate,UITableViewDataSource {
var items = ["Chilli and Lemon"]
#IBOutlet var tableView:UITableView!
#IBOutlet weak var lblRestaurantNames: UILabel!
#IBOutlet weak var mapView: UIButton!
var cellIdentifier = "cell"
init() {
super.init(nibName : "NewOrdersViewControllers", bundle:nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "tableCell", bundle: nil)
self.tableView.registerNib(nib, forCellReuseIdentifier: cellIdentifier)
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
#IBAction func mapPush(sender: AnyObject) {
let mapVC = MapViewController()
self.navigationController?.pushViewController(mapVC, animated: true)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:tableCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! tableCell
//cell.textLabel?.text = self.items[indexPath.row] as! String
cell.RestaurantLbl.text = self.items[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}
I have done it using xib and it shows the following error.
Could not cast value of type 'UITableViewCell' (0x1fe82bc)
In your viewDidLoad() method you register 2 different cell types for the same reuseIdentifier, so the last one (UITableViewCell) takes effect. That's why in tableView:cellForRowAtIndexPath: the cells being dequeued are also of UITableViewCell class and may not be cast to your custom cell class.
Try to remove the line:
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
it should fix your problem and let the tableView dequeue the correct cells.
Hello I started to learn swift and for a small project and i'm using a UITableView but I'm having an error when I try to register a nib that has my prototype cell (vwTblCell.xib)
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP,subcode=0x0)
This is where I get the error:
tableView.registerNib(nib, forCellReuseIdentifier: "Cell")
And this is the code that I use.
ViewController.swift
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
var nib = UINib(nibName: "vwTblCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "Cell")
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:TblCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as TblCell
cell.lblCell.text = self.items[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("Row \(indexPath.row) selected")
}
func tableView(tableView:UITableView!, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 44
}
}
TblCell.swift
class TblCell: UITableViewCell {
#IBOutlet weak var lblCell: UILabel!
#IBOutlet weak var btnCell: UIButton!
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
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
}
}
Fixed: It seems like I forgot to add a referencing outlet in the storyboard