Can you make a TableView in a custom cell? - ios

I have a custom TableViewCell. Inside of this, I want to put another TableView, but I'm having problems.
I have something like this:
import UIKit
class ByteCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var game: UIImageView!
#IBOutlet weak var TableView: UIView!
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 tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
}
First of all, I can't write:
tableView.delegate = self
tableView.dataSource = self
anywhere in here, so I can't modify the tableView at all.
Secondly, the TableView that does appear, doesn't have any rows, and can't be scrolled. I essentially want to make a scrollable TableView inside of a custom cell which is inside of a TableView.
Is this possible?
Thanks!

You can absolutely put a UITableView inside UITableViewCells
Where to put .delegate = self depends how you created the cell.
If you created it programmatically then use override init
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
}
If however your load the cell from nib or storyboard then use initWithCoder
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
}
return self;
}
Just a note, you are setting yourself up for a bumpy road. Its entirely possible nonetheless so good luck!

Related

TableView doesn't show my Data from Realm

i have one problem: my tableView doesn't show any data from realm database. But i guess the problem is in cell.
class ClientViewController: UITableViewController {
#IBOutlet var table: UITableView!
var clientsInfo: Results<Client> {
get {
return realm.objects(Client.self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(myCell.self, forCellReuseIdentifier: "cell")
table.delegate = self
table.dataSource = self
table.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: myCell.reuseIdentifier, for: indexPath) as! myCell
let info=clientsInfo[indexPath.row]
cell.todoLabel.text = info.firstName
return cell
}
}
class myCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
static let reuseIdentifier = "cell"
#IBOutlet weak var todoLabel: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}
There is a few things wrong in your code,
First:
You're using a UITableViewController, by default this already has a tableView, so you don't need to declare a new tableView like you did
#IBOutlet var table: UITableView!
Second:
In you viewDidLoad you're registering the cell for the default tableView and using your declared table for dataSource and delegate, this won't work. I recommend you remove the table you create and use the default so your viewDidLoad would look like this:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(myCell.self, forCellReuseIdentifier: "cell")
self.tableView.delegate = self
self.tableView.dataSource = self
}
and Third:
you're missing the implementation of :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
In this code you forgot to implement tableView(numberOfRowsInSection:) method, so it returns 0 by default and your tableview(cellForRowAt:) method never called.
AND
Maybe this is not about your question but;
You used UITableView variable(name is table) in UITableView. It's unneccessary, because UITableView already has a UITableView(name is tableView). And you'have registered your cell into tableView, but it seems you try to dequeue this cell from table.

UITableViewCell not visible in UITableView

I have a UITableView on the ViewController. Here is complete code
import UIKit
class UnitTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var unitTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.unitTable.register(UnitCell.self, forCellReuseIdentifier: "UnitCell")
self.unitTable.delegate = self
self.unitTable.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = unitTable.dequeueReusableCell(withIdentifier: "UnitCell", for: indexPath) as! UnitCell
cell.unitNameLbl?.text = "TEST"
return cell
}
}
But unfortunately my custom cell is not visible. I've put green background colour to be sure that constraints are right.
Here is my UnitCell code
import UIKit
class UnitCell: UITableViewCell {
#IBOutlet weak var unitNameLbl: UILabel?
#IBOutlet weak var unitNumberLbl: 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
}
}
What could be wrong if I can't see my custom cell?
try this following into viewDidLoad
unitTable.register(UINib(nibName: "yourCellClassName", bundle: nil), forCellReuseIdentifier: "UnitCell")
You can't directly use class name of cell because you'r using XIB of cell so you must need to register cell with nib name like below.
let nib = UINib(nibName: "YourTableViewCellNibName", bundle: nil)
self.unitTable.register(nib, forCellReuseIdentifier: "UnitCell")
change registering cell to table code as below.
override func viewDidLoad() {
super.viewDidLoad()
self.unitTable.register(UINib(nibName: "UnitTable", bundle: nil), forCellReuseIdentifier: "UnitCell") // nibName should be exact name of xib file of your custom cell.
self.unitTable.delegate = self
self.unitTable.dataSource = self
}

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

Display custom UITableViewCell from an array of cells

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.

Resources