Assigning property of custom UITableViewCell - ios

I am using the below custom UITableViewCell without nib file.
I have no problem in viewing it in my UITableViewController.
My problem is with assigning a text to "name" label cell.name.text = "a Name" .. noting is assigned
Can you help me?
import UIKit
class ACMenuCell: UITableViewCell {
#IBOutlet var name : UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
name = UILabel(frame: CGRectMake(20, 10, self.bounds.size.width , 25))
name.backgroundColor = .whiteColor()
self.contentView.addSubview(name)
self.contentView.backgroundColor = .blueColor()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
super.layoutSubviews()
}
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
}
}

You might want to try this: Create a public function in a subclass of UITableViewCell, and inside this funxtion set the text to label.
(void)initializeCell
{
do whatever like setting the text for label which is a subview of tableViewCell
}
And from cellForRowAtIndexPAth, call this function on cell object:
// taking your code for demo
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let reuseIdentifierAC:NSString = "ACMenuCell"; var cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifierAC, forIndexPath:indexPath) as ACMenuCell cell = ACMenuCell(style: UITableViewCellStyle.Default, reuseIdentifier: reuseIdentifierAC) [cell initializeCell] return cell }
This approach has worked for me.

Related

Programmatic UITableView is showing one cell only

A Swift newbie here. I'm trying to learn how to create different UI elements programmatically. I've hit the following wall..
I have 2 .swift files, on one hand we have...
import UIKit
struct MyTableView {
let myCustomTable: UITableView = {
let aTable = UITableView()
aTable.register(MyCustomCell.self, forCellReuseIdentifier: "myCell")
return aTable
}()
}
// custom cell class, then add subviews (UI controls) to it
class MyCustomCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(aLabel)
aLabel.frame = CGRect(x:0,
y:0,
width:self.frame.width,
height:self.frame.height)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// stuff to add to the cell
let aLabel: UILabel = {
let lbl = UILabel()
lbl.text = "My Custom Cell"
lbl.backgroundColor = UIColor.yellow // just to highlight it on the screen
return lbl
}()
On the other hand, we have the following view controller...
import UIKit
class ViewControllerA: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let instanceOfViewControllerTable = MyTableView()
override func loadView() {
super.loadView()
view.frame = UIScreen.main.bounds
instanceOfViewControllerTable.myCustomTable.delegate = self
instanceOfViewControllerTable.myCustomTable.dataSource = self
instanceOfViewControllerTable.myCustomTable.frame = CGRect(x:0,
y:0,
width:self.view.frame.width,
height:self.view.frame.height)
self.view.addSubview(instanceOfViewControllerTable.myCustomTable)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
}
}
It builds and runs successfully, however, I'm getting the following result:
Now, my thinking is if I'm doing something wrong, the cell shouldn't appear at all. What I don't understand, why is it showing only on one cell in the array?
Your help is highly appreciated.
You are declaring aLabel as a global variable. That way, only one instance exists from it. Move it inside your cell's class declaration.
class MyCustomCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(aLabel)
aLabel.frame = CGRect(x:0,
y:0,
width:self.frame.width,
height:self.frame.height)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let aLabel: UILabel = {
let lbl = UILabel()
lbl.text = "My Custom Cell"
lbl.backgroundColor = UIColor.yellow // just to highlight it on the screen
return lbl
}()
}

Swift 2 nib in uitableview loads but won't allow interaction

I first built a normal custom cell with no nib and it worked perfectly. But now I need to reuse the same cell layout in various views so I'm trying to use a nib in stead of a regular prototype cell.
The cell does display, with information inside. But I can't interact with it. For example, I can't write in the text field. When I click, it just selects the whole cell (although I turned off the selection of the cell in the tableview options).
I tried different ways to init the cell, but it either crashes or does nothing.
Here is my code:
CelluleView (the custom cell)
class CelluleView: UITableViewCell {
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()
}
}
ViewController
class PersoViewController: UITableViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
}
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "CelluleView", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "Cellule")
tableView.dataSource = self
tableView.delegate = self
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellule = tableView.dequeueReusableCellWithIdentifier("Cellule", forIndexPath: indexPath) as! CelluleView
return cellule
}
}
One solution would be to enable selection in the table view.
Set the selection style to none
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = UITableViewCellSelectionStyle.None
}
Create an outlet for your textfield
#IBOutlet weak var textField: UITextField!
and connect it with the nib
Then in the cell respond to the selection and set the text field to become first responder
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
textField.becomeFirstResponder()
}

Empty Cells in TableView with Custom TableViewCell - Swift

I am currently learning Swift programatically. I am wanting to add a tableView to a viewController (for the purpose of being able to manipulate the constraints later) and customize the cells with a TableViewCell.
I can do this with my eyes closed when using the storyboard, but when I try to do it with just straight code I have empty cells.
My storyboard is comprised of one (1) empty viewController that has the custom class of ViewController
I have looked at others with similar issues but non of the solutions have worked. Would love to know what I am overlooking (probably something simple). Thanks in advance for the help!
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var tableView: UITableView = UITableView()
var items: [String] = ["Viper", "X", "Games"]
override func viewDidLoad() {
tableView.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
}
func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 50
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
//cell.textLabel?.text = self.items[indexPath.row]
cell.companyName.text = "name"
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
TableViewCell:
import UIKit
class TableViewCell: UITableViewCell {
var companyName = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
companyName.frame = CGRectMake(0, 0, 200, 20)
companyName.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(companyName)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Hello #Michael First thing is you should only use awakeFromNib when you are using a .xib(Nib) and in your case you are using custom class without such xib so, you should use
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
companyName = UILabel(frame: CGRectMake(0, 0, 200, 20))
contentView.addSubview(companyName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
also you should initialise your label before using it.
this will solve your problem.
Read apple's documentation for subclassing UITableViewCell here.
If you want your custom cell to load from some custom xib you do sometimes like:
tableView.registerNib(UINib(nibName: "CustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "CustomTableViewCell")
And you should have CustomTableViewCell.xib file where you have table view cell with reuse identifier CustomTableViewCell
Checkout how your cell's companyLabel is laid out. Does it exist or no?
In your code, I replaced companyLabel with default textLabel and it worked for me.
cell.textLabel!.text = self.items[indexPath.row]
I think awakeFromNib is not called because you do not register a nib but a class. Try this instead:
class TableViewCell: UITableViewCell {
let companyName = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Initialization code
companyName.frame = CGRectMake(0, 0, 200, 20)
companyName.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(companyName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

EXC_BAD_ACCESS in Custom UITableViewCell

I've been banging my head against a wall for the past day or so trying to figure out this problem, so I hope someone can help!
I'm just trying to create a custom subclass of a UITableViewCell, but my app keeps crashing with an EXC_BAD_ACCESS error in the init function of my custom TableViewCell. I'm on Xcode 7.01
DiscoverViewController.swift
import UIKit
class DiscoverViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let networkInterface: GfyNetwork = GfyNetwork()
var gfyArray: Array<GfyModel> = []
var tableView: UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.title = "Discover"
let navbar = self.navigationController!.navigationBar
navbar.tintColor = UIColor(red:0.32, green:0.28, blue:0.61, alpha:1.0)
networkInterface.getTrendingGfys("", completionHandler: printGfys)
tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .None
tableView.rowHeight = 260
tableView.contentInset = UIEdgeInsetsMake(10, 0, 10, 0)
tableView.registerClass(GfyTableViewCell.self, forCellReuseIdentifier: "gfycell")
self.view.addSubview(tableView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func printGfys(gfyJSON: Array<GfyModel>) -> Array<GfyModel> {
// Array of fetched gfys
self.gfyArray = gfyJSON
// Update Tableview
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
return gfyJSON
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.gfyArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier("gfycell", forIndexPath: indexPath) as? GfyTableViewCell else { fatalError("unexpected cell dequeued from tableView") }
cell.gfy = self.gfyArray[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
}
GfyTableViewCell.swift
import UIKit
class GfyTableViewCell: UITableViewCell {
let padding: CGFloat = 5
var gfy: GfyModel!
var bgView: UIView!
var imageURL: UIImageView!
var title: 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
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
self.init(style: style, reuseIdentifier: reuseIdentifier) // Error happens here
backgroundColor = UIColor.whiteColor()
selectionStyle = .None
bgView.frame = CGRectMake(8, 0, contentView.frame.width-16, 250)
bgView.layer.cornerRadius = 3
bgView.layer.borderColor = UIColor(red:0, green:0, blue:0, alpha:0.4).CGColor
bgView.layer.borderWidth = 0.5
bgView.clipsToBounds = true
bgView.backgroundColor = UIColor.whiteColor()
title.frame = CGRectMake(10, 210, bgView.frame.width-100, 10)
title.text = gfy.title
title.font = UIFont.systemFontOfSize(10)
imageURL.frame = CGRectMake(0, 0, bgView.frame.width, 200)
if let url = NSURL(string: gfy.thumbUrl) {
if let data = NSData(contentsOfURL: url){
imageURL.contentMode = UIViewContentMode.ScaleAspectFill
imageURL.image = UIImage(data: data)
}
}
contentView.addSubview(bgView)
bgView.addSubview(imageURL)
}
override func prepareForReuse() {
super.prepareForReuse()
}
override func layoutSubviews() {
super.layoutSubviews()
}
}
Any help would be much appreciated. The app works when using standard UITableViewCells, but as soon as I try to add custom tableviewcells, it blows up :(
edit:
This is what my stack looks like. I'm pretty sure I'm doing something wrong in my override init() function in GfyTableViewCell.swift, but I don't know what that is:
The problem here is that the init method calls itself. Replace the following line:
self.init(style: style, reuseIdentifier: reuseIdentifier)
with:
super.init(style: style, reuseIdentifier: reuseIdentifier)
If you call a method within itself it will recursively call itself until the program eventually crashes because of a stack overflow or running out of memory. It's not obvious why this crashes with EXC_BAD_ACCESS, but it's possible this leads to one instance failing to actually be allocated.
Wow, as I expected, it was a simple error on my part.
Instead of calling:
convenience override init(style: UITableViewCellStyle, reuseIdentifier: String?) { ... }
It seems like I need to ditch the convenience and just call:
override init(style: UITableViewCellStyle, reuseIdentifier: String?) { ... }
Then I can do as Anthony posted above and call super.init(style: style, reuseIdentifier: reuseIdentifier) without any errors.
Fix:For Custom TableviewCell in Xcode 7.1.1.
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let cellT = cell as! CustomTableViewCellName
//enter code here
}

Swift Custom UITableViewCell Programmatically works and shows in cell but Storyboard IBOutlet is nil and does not show in cell

In my custom cell swift file CustomTableView.swift, I can create programmatically the labels for my TableView but when I use IBOutlet in Storyboard the label becomes always nil
I am very sure that my cell is not nil
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var lblPostDate: UILabel!
var message: UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.message.frame = CGRectMake(0, 0, 100, 40);
self.message.backgroundColor = UIColor.brownColor()
self.message.text = "bla bla bla bla bla"
self.addSubview(self.message)
}
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
}
func setCell(postDate: String)
{
self.lblPostDate?.text = postDate
}
}
In the above code, the message can be seen in the cells but lblPostDate which is the IBOutlet can not be seen
I am sure about the delegate and datasource and custom cell identifier what so ever but it seems that the IBOutlets don't get initialized correctly. I can see that lblPostDate becomes nil when I debug
Is this a bug of XCode 6?
Here is how I call from my Controller
import UIKit
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var items = ["one","two","three","four"]
let kCellIdentifier: String = "CustomCell"
#IBOutlet weak var mTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.mTableView.registerClass(CustomTableViewCell.classForCoder(), forCellReuseIdentifier:kCellIdentifier)
//self.mTableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: kCellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomTableViewCell! = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier, forIndexPath: indexPath) as? CustomTableViewCell
if (cell == nil) {
self.mTableView.registerClass(CustomTableViewCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: kCellIdentifier)
}
if var label = cell.lblPostDate{
label.text = items[indexPath.row]
}
else{
cell.setCell(items[indexPath.row])
}
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 44
}
}
You have to link the lblPostDate with one label in your cell xib file.
That is insane, I deleted the register class code and it worked, I can't believe it
//self.mTableView.registerClass(CustomTableViewCell.classForCoder(), forCellReuseIdentifier:kCellIdentifier)
After commenting out the registerClass in my Controller, it doesn't call anymore the init function but creates the lblPostDate correctly indeed
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.message.frame = CGRectMake(0, 0, 100, 40);
self.message.backgroundColor = UIColor.brownColor()
self.message.text = "bla bla bla bla bla"
self.addSubview(self.message)
}
So I don't need anymore to create hard-code input objects.
It is interesting that all the tutorials, everywhere they suggest to register the class. Anyway,it worked!

Resources