Display custom UITableViewCell from an array of cells - ios

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.

Related

cellForRowAtIndexPath not showing Realm objects data

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

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

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()
}

Delegate didSet property of UIView not being called inside custom UITableViewCell

I've been banging my head on the desk for the past 2 hours trying to figure this out so any help will be greatly appreciated.
I'm using CVCalendar (the develop branch) and I'm trying to place the CalendarView inside a custom UITableViewCell so I can make it look something like this:
The problem I'm facing is that it doesn't set the delegate property when I call self.calendarView.calendarDelegate = self inside the custom UITableViewCell
I know it's not being set because I've placed a println inside the delegate didSet property that's not being outputted.
Here is the CalendarViewDelegate outlet inside the CalendarView
// MARK: - Calendar View Delegate
#IBOutlet weak var calendarDelegate: AnyObject? {
set {
if let calendarDelegate = newValue as? Delegate {
delegate = calendarDelegate
println("delegate did set property called")
}
}
get {
return delegate
}
}
Here is my code for the custom UITableViewCell I'm working with.
import UIKit
class CalendarCell: UITableViewCell {
var calendarView: CVCalendarView!
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
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = UIColor.redColor()
selectionStyle = .None
self.calendarView = CVCalendarView(frame: self.frame)
self.calendarView.calendarDelegate = self
self.calendarView.calendarAppearanceDelegate = self
self.calendarView.animatorDelegate = self
contentView.addSubview(calendarView)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
self.calendarView.commitCalendarViewUpdate()
}
}
Here is my UITableViewController code:
import UIKit
class CalendarTableViewController: UITableViewController {
#IBOutlet var myTableView: UITableView!
var items = ["Apple", "Banana"];
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.registerClass(CalendarCell.self, forCellReuseIdentifier: NSStringFromClass(CalendarCell))
self.myTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.myTableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func creatHeaderCell() -> UITableViewCell {
var headerCell = self.myTableView.dequeueReusableCellWithIdentifier(NSStringFromClass(CalendarCell)) as! CalendarCell
return headerCell
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if (indexPath.section == 0) {
return 300
}
return 44
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (section) {
case 0:
return 1
default:
return items.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (indexPath.section == 0) {
return self.creatHeaderCell()
}
let cell = self.myTableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel!.text = "Thomas"
// Configure the cell...
return cell
}
}
Your println statement is probably not reached because your if condition if let calendarDelegate = newValue as? Delegate is not true because what you pass in as calenderDelegate is a CalenderCell, not a Delegate or CVCalendarViewDelegate (typealias).
Additionally your CalendarCell does not conform to CVCalendarViewAppearanceDelegate and CVCalendarViewAnimatorDelegate.
You have to make your cell conform to those protocols to be able to set them as delegates.

Custom UITableViewCell in Swift programmatically

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.

Resources