I can't figure out why this custom cell is not being output.
I have a custom cell set up in a storyboard (no nib).
I have a text field and 2 labels which are nil when I try to access them in the custom cell class. I'm almost sure I have everything hooked up correctly, but still getting nil.
I've selected my table cell in the storyboard and set Custom Class to TimesheetTableViewCell
I've also control clicked on the table and set the datasource and delegate to be TimesheetViewController
My custom cell class:
import UIKit
class TimesheetTableViewCell: UITableViewCell {
#IBOutlet var duration: UITextField!
#IBOutlet var taskName: UILabel!
#IBOutlet var taskNotes: UILabel!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init?(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
println("Cell's initialised")// I see this
println(reuseIdentifier)// prints TimesheetCell
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func setCell(duration: String, taskName: String, taskNotes: String){
println("setCell called")
self.duration?.text = duration
self.taskName?.text = taskName
self.taskNotes?.text = taskNotes
}
My controller:
class TimesheetViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
#IBOutlet var timesheetTable: UITableView!
var items = ["Item 1", "Item2", "Item3", "Item4"]
override func viewDidLoad() {
super.viewDidLoad()
self.timesheetTable.registerClass(TimesheetTableViewCell.self, forCellReuseIdentifier: "TimesheetCell")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TimesheetCell", forIndexPath: indexPath) as TimesheetTableViewCell
println(items[indexPath.row]) // prints corresponding item
println(cell.duration?.text) // prints nil
cell.setCell(items[indexPath.row], taskName: items[indexPath.row], taskNotes: items[indexPath.row])
return cell
}
The problem is this line:
self.timesheetTable.registerClass(TimesheetTableViewCell.self, forCellReuseIdentifier: "TimesheetCell")
Delete it. That line says: "Do not get the cell from the storyboard." But you do want to get the cell from the storyboard.
(Make sure, however, that the cell's identifier is "TimesheetCell" in the storyboard, or you'll crash.)
Pretty sure that you need to remove the line
self.timesheetTable.registerClass(TimesheetTableViewCell.self, forCellReuseIdentifier: "TimesheetCell")
from viewDidLoad().
Related
I'm trying to use Realm to store user data when they create something. I know that Realm is saving the right data and I can access the certain data I need, i.e. the name I'm trying to display on a label in the custom cell.
My code for the view controller
class MeetupListViewController: ToolbarTabSuper, UIViewControllerTransitioningDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
#IBOutlet weak var toolbarView: UIToolbar!
var realm: Realm!
lazy var results: Results<Meetup> = { self.realm.objects(Meetup).sorted("meetupName") }()
var meetups = [Meetup]()
var items: [String] = ["We", "Heart", "Swift"]
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Meetup List"
self.toolbarView.barTintColor = tabToolbarColor
}
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 60
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.results.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! MeetupCellTableViewCell
let item = results[indexPath.row]
cell.label?.text = item.meetupName
return cell
}
My code for the custom cell
class MeetupCellTableViewCell: UITableViewCell {
var meetupName = UILabel()
#IBOutlet var label: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(meetupName)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
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
}
}
The reuse identified is set in the storyboard where I created the label with an image I want to use. It seems the cellForRowAtIndexPath function isn't even being called. Everything seems to be working from what I've looked online, but it's simply not showing up.
You should set the delegate and the data source to self in order to hook up the tableView with your functions if you are using them inside a ViewController.
It should look like that:
self.tableView.delegate = self
self.tableView.dataSource = self
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
I have an UIViewController that creates a custom UITableViewCell and insert it into an array. Then I've a UITableViewController and I want to show cells from previous array. The problem is that in tableView(tableView:cellForRowAtIndexPath) I don't want to use dequeueReusableCellWithIdentifier because I just want to get the cells from the array and use them.
Unfortunately this doesn't work. I read dequeueReusableCellWithIdentifier permits to save in memory only the necessary cells.
I'm thinking about a method to "push" my custom cells in that queue but I can't find anything. So at the end I'm not able to show my custom cells.
Note: I can't obtain the cell using dequeueReusableCellWithIdentifier and than set each properties because one of them is a UIProgressView and it's updated within my custom cell class so I need to display that cell.
This is the code within the UIViewController which create the custom cell and set it into the array:
//here I create my custom cell (DownloadTVCell)
let cell = DownloadTVCell(style: UITableViewCellStyle.Default, reuseIdentifier: "DownloadRootTVC_IDcell")
cell.nomeFileInDownloadLabel.text = nomeCompletoMp3
//this is a method in DownloadTVCell that starts a download task
cell.createDownloadTask()
//here i got the navigationController in order to obtain the instance of
//the UITableViewController. In this method when a user tap on the
//UITableViewController it's already instantiated
let nc = self.tabBarController!.viewControllers![1] as! UINavigationController
let drtvc = nc.topViewController as! DownloadRootTVC
//now drtvc is the instance of DOwnloadRootTVC which is my custom UITableViewController
//add the cell to the array
drtvc.listOfCellsDownlaod.append(cell)
This is my custom cell:
class DownloadTVCell: MGSwipeTableCell, NSURLSessionDownloadDelegate {
//******************************************************************
// IBOUtlet
//******************************************************************
#IBOutlet var nomeFileInDownloadLabel: UILabel!
#IBOutlet var quantitaScaricataLabel: UILabel!
#IBOutlet var progressView: UIProgressView!
private var downloadTask: NSURLSessionDownloadTask?
//******************************************************************
// METODI
//******************************************************************
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
log("ACTION", text: "Metodo chiamato")
build()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
log("ACTION", text: "Metodo chiamato")
build()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
private func build() {
self.nomeFileInDownloadLabel = UILabel()
self.quantitaScaricataLabel = UILabel()
self.progressView = UIProgressView()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//here there is some logic for download
...
}
And finally this is my custom UITableView:
class DownloadRootTVC: UITableViewController {
//******************************************************************
// PROPRIETA' GENERICHE
//******************************************************************
var listOfCellsDownlaod = [DownloadTVCell]()
//******************************************************************
// METODI
//******************************************************************
override func viewDidLoad() {
log(text: "self.listOfCellsDownlaod.count: \(self.listOfCellsDownlaod.count)")
self.tableView.delegate = self
self.tableView.dataSource = self
self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reloadTableData:", name: "reload", object: nil)
//self.tableView.registerClass(DownloadTVCell.self, forCellReuseIdentifier: "DownloadRootTVC_IDcell")
super.viewDidLoad()
}
func refresh(sender:AnyObject) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
func reloadTableData(notification: NSNotification) {
tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listOfCellsDownlaod.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCellWithIdentifier("DownloadRootTVC_IDcell", forIndexPath: indexPath) as! DownloadTVCell
//I just want to return my custom cell
return self.listOfCellsDownlaod[indexPath.row]
}
}
Instead of adding UITableViewCells to your array you should probably add only the cell identifiers and then dequeue the cells in cellForRowAtIndexPath and do the set up there. If you can't retrieve the information to populate the cells in cellForRowAtIndexPath, then create a class or object to save the cell identifiers together with all the info you need to populate the cells (texts for labels, image file names for image views, etc).
Remember that table view cells are view objects and you should not include logic in view objects. Put all the logic into a separate object and then just fill the cells as needed.
I'm looking to programmatically create a UITableView and corresponding custom UITableViewCell in Swift. The table view is working great, but it doesn't seem like the cell labels are instantiating - they come back as nil.
I also don't know how to refer to the content view size when sizing elements.
UITableViewCell
import UIKit
class BusUITableViewCell: UITableViewCell {
var routeNumber: UILabel!
var routeName: UILabel!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
routeName = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 50)) // not sure how to refer to the cell size here
contentView.addSubview(routeNumber)
contentView.addSubview(routeName)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
UITableView delegate and source
import Foundation
import UIKit
class BusUITableView: NSObject, UITableViewDelegate, UITableViewDataSource {
var routeService: RouteService = RouteService()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var busRoutes: [Route] = routeService.retrieve()
return busRoutes.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:BusUITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as BusUITableViewCell
var busRoutes: [Route] = routeService.retrieve()
cell.routeName.text = "test" // test string doesn't work, returns nil
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
View Controller
mainTableView.registerClass(BusUITableViewCell.self, forCellReuseIdentifier: "cell")
If you aren't linking to a prototype cell in a storyboard then you need to register the class for your cell against your tableView using registerClass(_ cellClass: AnyClass,
forCellReuseIdentifier identifier: String)
In your case you would use something like this
tableview.register(BusUITableViewCell.self, forCellReuseIdentifier:"cell")
Also, without a NIB file, awakeFromNib won't be invoked.
Edit: .registerClass() has been renamed to .register()
Considering you are doing this "programmatically" (no nib file), you're awakeFromNib() will never invoke. You can create a nib, and link it to this backing file, and still create and use the cell programmatically. Or ... choose a different place (like the initializer) to create and add subviews to the cell.
I'm having an issue with custom TableViewCell in Swift. I'm trying to display a custome TableViewCell in a TableView but that doesn't work well. I got a grey square on the screen... I found some answers on the Internet that recommend to disable Auto-Layout. I did it but now, my cell is displayed but there is a mess with the height of the cells. As you can see, my cell that is supposed to have red background is displayed on the height of 3 cells while the background is on only 1 cell. The height of the cell and the Row Height are both set to 150px.
With Auto-Layout: Without Auto-Layout:
Here is the Cell code:
class CharacterDescription : UITableViewCell {
#IBOutlet var imageProfile: UIImageView!
#IBOutlet var name: UILabel!
#IBOutlet var hp: UILabel!
#IBOutlet var damages: UILabel!
#IBOutlet var range: UILabel!
#IBOutlet var mp: UILabel!
#IBOutlet var critChances: UILabel!
#IBOutlet var critModifier: UILabel!
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: UITableViewCellStyle.Value1, reuseIdentifier: reuseIdentifier)
}
}
And the TableViewController code:
class CharacterDescriptionsViewController : UITableViewController, UITableViewDataSource, UITableViewDelegate {
var userProfile: UserProfile!
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override init() {
super.init()
}
override func viewDidLoad() {
var nibName = UINib(nibName: "CharacterDescription", bundle:nil)
self.tableView.registerNib(nibName, forCellReuseIdentifier: "CharacterDescription")
}
override func numberOfSectionsInTableView(tableView: UITableView?) -> Int {
return 1
}
override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return userProfile.characters!.count
}
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
var cell = self.tableView.dequeueReusableCellWithIdentifier("CharacterDescription", forIndexPath: indexPath) as CharacterDescription
//!TODO: Init of cell
return cell
}
}
You have to override TableView.heightForRowAtIndexPath to return the height of your custom cell.