Cant find Cell Identifier(No storyboard) - ios

Hi I hav an issue where I cant seem to find the cell identifier to put into my table. I have 5 files.I am new to xcode but I need to code without a storyboard for my school project.
I am following the tutorial here -https://www.youtube.com/watch?v=kYmZ-4l0Yy4
ActiveCasesController.swift
//
// ActiveCasesController.swift
//
// Created by fypj on 29/3/18.
// Copyright © 2018 fypj. All rights reserved.
//
import UIKit
class ActiveCasesController:UIViewController, UITableViewDelegate, UITableViewDataSource {
let elements = ["horse", "cat", "dog", "potato","horse", "cat", "dog", "potato","horse", "cat", "dog", "potato"]
var acView = ActiveCasesView()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
acView.tableView.delegate = self
acView.tableView.dataSource = self
}
func setupView() {
let mainView = ActiveCasesView(frame: self.view.frame)
self.acView = mainView
self.view.addSubview(acView)
acView.setAnchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ActiveCaseCellView = tableView.dequeueReusableCell(withIdentifier: "customCell") as! ActiveCaseCellView
cell.cellView.layer.cornerRadius = cell.cellView.frame.height / 2
cell.lblCell.text = elements[indexPath.row]
return cell
}
}
ActiveCasesView.swift
import UIKit
class ActiveCasesView: UIView{
#IBOutlet var mainView: UIView!
#IBOutlet weak var tableView: UITableView!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
//scrollView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
Bundle.main.loadNibNamed("ACView", owner: self, options: nil)
addSubview(mainView)
mainView.frame = self.bounds
mainView.autoresizingMask = [.flexibleHeight,.flexibleWidth]
}
}
ACView.xib
ActiveCaseCellView.swift
import UIKit
class ActiveCaseCellView:UITableViewCell {
#IBOutlet weak var cellView: UIView!
#IBOutlet weak var lblCell: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
ACViewCell.xib
Error Message
Image of me adding register not sure whether i added correctly..

use the cell identifier by selecting you cell in storyboard.
it must be same in viewcontroller and storyboard tableview cell.

Open your .xib file and drag and drop UITableViewCell not UIView.
After that select attribute inspector you will see cell identifier textbook where you need to set cell identifier
Don't forget to register table view cell before using it!!
self.tableView.registerClass(<YourCustomCellClass>, forCellReuseIdentifier: "cellIdentifier")
or
let nib = UINib(nibName: "YourNibFileName", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cellIdentifier")

You need to call register(_:forCellReuseIdentifier:) on your tableView to make it find the requred cells upon calling dequeue....
You can set the reuse identifier in the xib or storyboard where your cell is defined.

Set cell identifier in Xib
Register Xib with UITableView in viewDidLoad :
tableView.register(UINib(nibName: "ActiveCaseCellView", bundle: Bundle.main), forCellReuseIdentifier: "customCell")

Related

How to set customView in UITableViewCell with Swift

I have UITableView, UITablaViewCell, CustomView
and UITableViewCell includes customView.
I'm trying to put Product's data to cell with my function not cellForRowAt.
Cell shows just origin view ProductView.xib with empty data
Please help.
ViewController.swift
struct Product {
let brand: String
let product: String
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! ProductTableViewCell
// this line is not work
// productView is not update
cell.productView = createProductView(product: product)
return cell
}
func createProductView(product: Product) -> ProductView {
let productView = ProductView()
productView.brandLabel.text = product.brand
productView.productLabel.text = product.product
return productView
}
UITableViewCell.swift
class ProductTableViewCell: UITableViewCell {
#IBOutlet var productView: ProductView!
}
ProductView.swift
class ProductView: UIView {
#IBOutlet weak var productView: UIView!
#IBOutlet weak var brandLabel: UILabel!
#IBOutlet weak var productLabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
let bundle = Bundle(for: ProductView.self)
bundle.loadNibNamed("ProductView", owner: self, options: nil)
addSubview(productView)
productView.frame = self.bounds
}
There are multiple issues with your code
Issue 1: cellForRowAt IndexPath gets called multiple times, with your code you will end up creating a new ProductView every time tableView is scrolled (cell is reused). instead you can create product view only once and update its label every time cell is reused
Issue 2: In ProductView's commonInit you set the frame using productView.frame = self.bounds self.bounds will always be(0,0,0,0). Because you have instantiated ProductView as ProductView()
Issue 3: createProductView is supposed to return an instance of ProductView hence the method signature is invalid so you should change it from func createProductView(product: Product) -> ProductView() to func createProductView(product: Product) -> ProductView as already suggested in answer above
What can be better solution?
class ProductTableViewCell: UITableViewCell {
var productView: ProductView!
func updateProductView(product: Product) {
productView.brandLabel.text = product.brand
productView.productLabel.text = product.product
}
override func prepareForReuse() {
super.prepareForReuse()
productView.brandLabel.text = nil
productView.productLabel.text = nil
}
override func awakeFromNib() {
super.awakeFromNib()
self.productView = createProductView()
self.addSubview(self.productView)
self.productView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.productView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
self.productView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
self.productView.topAnchor.constraint(equalTo: self.topAnchor),
self.productView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
func createProductView() -> ProductView {
return ProductView()
}
}
Finally in your cellForRowAtIndexPath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! ProductTableViewCell
//assuming you already have a product for index path
cell.updateProductView(product: product)
return cell
}
EDIT:
As OP is facing issue with loading nib from bundle updating the answer here.
In your ProductView common init change the way you access bundle from
Bundle(for: ProductView.self) to Bundle.main as shown below
class ProductView: UIView {
#IBOutlet weak var productView: UIView!
#IBOutlet weak var brandLabel: UILabel!
#IBOutlet weak var productLabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
Bundle.main.loadNibNamed("ProductView", owner: self, options: nil)
addSubview(productView)
}
Few things to take care
Ensure you have an XIB named ProductView in your bundle
Ensure you have set its file owner to ProductView

UITableView with customized cell inside Custom UIView Xcode

I have been trying to incorporate tableview inside uiview xib file in Xcode.
I was able to get the table shown but unable to include customized cell in it.
here is my main code:
class homemoments:UIView, UITableViewDataSource, UITableViewDelegate {
var posts: Posts!
let screenHeight = UIScreen.main.bounds.height
let screenWidth = UIScreen.main.bounds.width
#IBOutlet weak var tableView: UITableView!
override init(frame: CGRect) {
super.init(frame: frame)
posts = Posts()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "newsfeedcell")
commitint()
}
//initWithCode to init view from xib or storyboard
required init?(coder: NSCoder) {
super.init(coder: coder)
commitint()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "newsfeedcell") as! NewsfeedTableViewCell
cell.set(post: posts.postsArray[indexPath.row])
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.postsArray.count
}
func commitint(){
let viewFromXib = Bundle.main.loadNibNamed("homemoments", owner: self, options: nil)![0] as! UIView
viewFromXib.frame = self.bounds
addSubview(viewFromXib)
}
}
when I run this code, my tableview.register returns an error saying that tableview is nil.
which is weird because initially my tableview.delegation & datasource doesn't work either. so I manually add them by dragging the tableview to file owner from the xib file to set those.
is this because we are not able to create customized cell for the tableview in xib? since I did notice that the tableview in xib doesn't have prototyped mode compared to uiviewcontroller.
UPDATES
My tableview now shows with the exception that there is no cell content shown.
I have searched and was told that to use
tableView.register(UINib(nibName: "momentcell", bundle:nil),forCellReuseIdentifier:"momentcell")
see below:
override init(frame: CGRect) {
super.init(frame: frame)
commitint()
posts = Posts()
tableView.register(UINib(nibName: "momentcell", bundle:nil),forCellReuseIdentifier:"momentcell")
}
//initWithCode to init view from xib or storyboard
required init?(coder: NSCoder) {
super.init(coder: coder)
commitint()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "momentcell") as! momentcell
//cell.set(post: posts.postsArray[indexPath.row])
cell.backgroundColor = .blue
return cell
}
here's the screenshot of my cell xib file
import UIKit
class momentcell: UITableViewCell {
}
and now the error is saying that
let cell = tableView.dequeueReusableCell(withIdentifier: "momentcell") as! momentcell
this is nil
Tableview will not be initialized yet In init if you are using storyboard
Please try to access it from awakefromnib or viewdidload
The problem is that you try to access tableView before xib is loaded.
Try this
override init(frame: CGRect) {
super.init(frame: frame)
posts = Posts()
commitint()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "newsfeedcell")
tableView.dataSource = self
tableView.delegate = self
}
If it's not working than probably you have incorrect xib set up. You can reference to this article, it explains how to load UIView from xib quite detailed

Not able to use Custom Cell with UITableView

I am trying to populate uitableview with custom but getting the following error:
Fatal error: Use of unimplemented initializer 'init(style:reuseIdentifier:)' for class 'Appname.PostCellView'
Code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! PostCellView
return cell
}
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(PostCellView.self, forCellReuseIdentifier: "Cell")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Post View Cell: (this class is loaded in the File's Owner of the view)
import UIKit
protocol PostCellViewDelegate: class {
}
class PostCellView: UITableViewCell {
weak var delegate: PostCellViewDelegate?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let _ = commonInitialization()
}
func customise(imageName : String , color : UIColor, logoLabelValue : String, websiteValue: String)
{
}
func commonInitialization() -> UIView
{
let bundle = Bundle.init(for: type(of: self))
let nib = UINib(nibName: "PostCellView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
return view
}
}
Please help me finding what's wrong with my code and how I should rectify the same.
Override init(style:reuseIdentifier:)
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Code
}
Please check this tutorial
Please shift the call to commonInitialization() from initWithCoder to method awakeFromNib. Also remove the initWithCoder method
In your PostCellView code add this method and remove the initWithCoder.
override func awakeFromNib() {
super.awakeFromNib()
let _ = commonInitialization()
}

How to load custom cell ( xib) in UICollectionView cell using swift

I have created a small sample project using Swift. I have created an "MyCustomView" as xib which contains label, button and imageView as shown in below code:
import UIKit
#IBDesignable class MyCustomView: UIView {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var btnClick: UIButton!
#IBOutlet weak var myImageView: UIImageView!
var view:UIView!
#IBInspectable
var mytitleLabelText: String? {
get {
return lblName.text
}
set(mytitleLabelText) {
lblName.text = mytitleLabelText
}
}
#IBInspectable
var myCustomImage:UIImage? {
get {
return myImageView.image
}
set(myCustomImage) {
myImageView.image = myCustomImage
}
}
override init(frame : CGRect)
{
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup()
{
view = loadViewFromNib()
view.frame = self.bounds
// not sure about this ?
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "MyCustomView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
Attached the image of xib for the reference.
In StoryBoard -> ViewController added UIViewCollection which as shown in the below image. In this viewcollection, I need that orange color cell to contain my custom xib to be loaded at runtime.
How do I achieve this?
New Modified code as suggested by Sandeep
// 1
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.register(UINib(nibName: "MyCustomView", bundle: nil), forCellWithReuseIdentifier: "myCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView
cell.lblName.text = "MyNewName"
return cell
}
}
// 2
import UIKit
#IBDesignable class MyCustomView: UICollectionViewCell {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var btnClick: UIButton!
#IBOutlet weak var myImageView: UIImageView!
var view:UIView!
#IBInspectable
var mytitleLabelText: String? {
get {
return lblName.text
}
set(mytitleLabelText) {
lblName.text = mytitleLabelText
}
}
#IBInspectable
var myCustomImage:UIImage? {
get {
return myImageView.image
}
set(myCustomImage) {
myImageView.image = myCustomImage
}
}
}
Here is what you can do,
Change your MyCustomView class to be a subclass of UICollectionViewCell and not UIView.
Remove override init(frame : CGRect),required init?(coder aDecoder: NSCoder),func xibSetup(),func loadViewFromNib() -> UIView from MyCustomView
I seriously could not understand how are you using your setter and getter for mytitleLabelText and myCustomImage. If its of no use get rid of it as well.
Finally you will be left with just IBOutlets in MyCustomView.
For better coding practice change the name from MyCustomView to MyCustomCell (optional)
Go to your xib, select the xib and set its class as MyCustomView.
In the same screen change file owner to yourView controller hosting collectionView
In ViewDidLoad of your viewController register your nib.
self.collectionView.registerNib(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")
In cellForItemAtIndexPath,
let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView
cell.lblName.text = "bla bla" //access your Cell's IBOutlets
return cell
Finally in order to control the size of cell either override the delegate of collectionView or simply go to your collectionView select the collectionCell in it and drag it to match your dimension :) Thats it :)
Happy coding. Search tutorials for better understanding. I can't explain all delegates as I'll end up writing a blog here.
For Swift 4.0
in viewDidLoad:
//custom collectionViewCell
mainCollectionView.register(UINib(nibName: "your_customcell_name", bundle: nil), forCellWithReuseIdentifier: "your_customcell_identifier")
in cellForItemAt indexPath:
let cell : <your_customcell_name> = mainCollectionView.dequeueReusableCell(withReuseIdentifier: "your_customcell_identifier", for: indexPath) as! <your_customcell_name>
And dont forget to set identifier for your custom cell in xib section.
One line approach if you have to register multiple cells.
extension UICollectionViewCell {
static func register(for collectionView: UICollectionView) {
let cellName = String(describing: self)
let cellIdentifier = cellName + "Identifier"
let cellNib = UINib(nibName: String(describing: self), bundle: nil)
collectionView.register(cellNib, forCellWithReuseIdentifier: cellIdentifier)
}
}
Steps on how to use
Name your Cell identifier as "YourcellName" + "Identifier" eg:
CustomCellIdentifier if your cell name is CustomCell.
CustomCell.register(for: collectionView)
For Swift 4.2
in viewDidLoad
self.collectionView.register(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")
in cellForItemAt indexPath:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "your_reusable_identifier", for: indexPath) as! MyCustomView
And of course as #Raj Aryan said:
don't forget to set identifier for your custom cell in xib section.

How to Custom UITableViewCell in swift

I'm a newbie in swift, and i try to custom UITableViewCell, i see many tutorial in youtube and internet. But i can't do it, i tried to fix a lot of way but nothing is change.
here is my code :
class movieViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var categories = ["Action", "Drama", "Science Fiction", "Kids", "Horror"]
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var btnMenu: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
btnMenu.target = self.revealViewController()
btnMenu.action = Selector("revealToggle:")
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.revealViewController().rearViewRevealWidth = 200
self.tableView.registerClass(CategoryRow.self, forCellReuseIdentifier: "Cell")
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return categories.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CategoryRow
cell.labelA.text = self.categories[indexPath.row]
cell.labelB.text = self.categories[indexPath.row]
return cell
}
CategoryRow.swift:
class CategoryRow: UITableViewCell {
var labelA: UILabel!
var labelB: 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
}
}
and my bug :
It seem that you don't have xib. And you just declare your label but you don't init it. So labelA and labelB will nil. it make crash.
If you don't want xib, You must implement two function in CategoryRow like code below:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.labelA = UILabel(frame: CGRectMake(0,0, self.contentView.frame.size.width, self.contentView.frame.size.height))
//Same here for labelB
self.contentView.addSubview(labelA)
}
Another way is you create xib UITableCiewCell with name same with your class. And set this cell is your class. You design labelA and labelB in this xib and drage outlet into class. And you modify in viewDidLoad
self.tableView.registerNib(UINib(nibName: "nameYourxib"), forCellReuseIdentifier: "Cell")
You haven't linked labelA inStoryboard.
Creating an Outlet Connection
You have not allocate the labelA or labelB. Thats why show the error. Connect your label with you UI like this:
#vien vu answer is right but what to do without XIB ?? Here is the complete solution for Custom cell in swift
You need to add delegate a datasource in viewDidLoad
viewDidLoad() {
self.tableView.delegate = self
self.tableView.datasource = self
}
and you need to create the labelA and labelB by outlets not variables. Hold control and drag from Storyboard to the corisponding file and let go, choose outlet and give it the name labelA and labelB

Resources