swift return costum cell from storyboard - ios

i have a static table view with 2 sections. Each section has two rows. The first row is a date picker cell (DVDatePickerTableViewCell). Now i put manually a textfield into the second cell.
In the view controller i load the cells with this code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellID : NSString = "Cell"
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(CellID) as UITableViewCell
if indexPath.section == 0 && indexPath.row == 0 {
return cells[indexPath.section][indexPath.row] as UITableViewCell
}
return cell
The Cell with the identifier "Cell" has the textfield in it. But when the table view is load, the first cell works perfectly but the others are just empty cells. How can i return the cells with the "style", which i created in the storyboard?
Thanks in advance!

In case you would like to use static cells in your table view, make sure that "Static cells" is selected in your table view settings:
In this case you don't need to implement override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell, table view will handle cells loading and displaying automatically.
To link any outlets from Interface Builder to your code you don't even have to create custom classes for your cells, you can link your views from table view's cells in Interface Builder directly to your view controller:

Related

Reusing dynamic TableViewCells without having to maintain of each cell's state in Controller

I have a UITableView that uses a cell that has 3 expandable and collapsable subviews in them. I would prefer to maintain the state of these views in my UITableViewCell class itself (states as in collapsed or expanded)
Since they are reusable cells, currently, if I expand view 1 in cell A, and then scroll down to cell B, it's view 1 will be expanded. I don't want this. I want it collapsed. But, if I scroll back up to cell A, I want it to still be expanded.
Other than storing all of these states in an array or dictionary
var expandedViewOneCells: [Int] = []
var expandedViewTwoCells: [Int] = []
etc.
I would prefer to have the cells essentially of act individually and maintain their own state... But how would I do this when cells are reused? Keep in mind, I will always only have at most 3 of these kinds of cells, so can I set something like only reuse after 3 cells.
Would it be wise to keep an array of the cells I load, and then on cellForRowAt load the cell from that array based on the index and return it?
In your func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell function try not to deque a cell but create a new instance of your cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = MyCustomCell()
return cell
}
If you are loading your cell from a xib file you need a way to create your custom cell from that nib. Add the following method to your CustomCell class
static func loadFromNib() -> RequestTableViewCell {
let nib = UINib(nibName: "\(MyCustomCell.self)", bundle: Bundle.main)
let cell = nib.instantiate(withOwner: self, options: nil)[0] as! MyCustomCell
return cell
}
Then in your func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell this will create a new cell for every row and not reuse a cell when scrolling
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = MyCustomCell.loadFromNib()
return cell
}
A solution like this may not be optimal if your table view has a lot of rows but for a SMALL amount of rows this should be okay
I see 2 solutions to your problem:
Use 3 View Controllers. They should never get destroyed, and add / remove the corresponding VC's view on top of the .contentView of the cell as it appears or goes off-screen. See the solution here http://khanlou.com/2015/04/view-controllers-in-cells/ The Custom Cell itself is just a view, shouldn't really be concerned with the state, but if we move that logic to a View Controller - we should be fine, an we are not violating MVC. Plus, the View Controller can keep track of the height of the view, based on the state, and heightForRow(at:) can ask it for that
I'd use a Stack View as this is a perfect scenario for it. I'd probably represent the Cell itself as another stack view. Not sure exactly what the views look like and how they change, but it may end up as simple as hiding / unhiding the second view from the Stack View that represent a "cell".

How to set conditional static tableview cell content in storyboard?

I have made a tableview controller with static cells in my storyboard(I used static cells because its a settings screen where almost all the cells are static except one). There is one cell which takes different contents(from different UITableViewCell xib s) on different conditions. If I try to assign that cell some value in func tableView(tableView: UITableView, cellForRowAtIndexPath..., then I ve to set the other cells also. Is there a way where I can set only one cell and take the other cells as how they are in the xib.?
Also if at all it is possible can I assign a static cell with contents of a cell's xib in case I already have one made?
use willdisplaycell function
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.row == 5){ //your row where you want to change
}
}
other row will be as it is in stroybord
There is no need of implementing cellForRowAtIndexPath for UITableViewController with static cells. You only need to make IBOutlet of your cell labels or the controls whose value you want to change at runtime on conditional bases. After that in UITableViewController class viewDidLoad or ViewDidAppear change the required control values based on your conditions.

How do I fix the illegal configuration?

I have a .xib file and I want that to be a table view controller, but when I create a table view controller in the .xib file I get the error:
Table views with embedded sections and cells are only supported in storyboard documents.
How do I fix this?
Below is my code for the actual table view:
self.add = [Play(name: title!), Play(name: artist!), Play(name: album!)]
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.add.count
//return count of objects in array
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
var play: Play
play = add[indexPath.row]
cell.textLabel?.text = play.name
return cell
}
Xibs are sort of out dated, and when they were invented, didn't have prototype cells that you could make in the Interface Builder.
When storyboards were introduced this functionality was made as well, except not back ported to the xib editor, so you can't use prototype cells in a xib unfortunately, you will need to make separate xibs for the cells layout.

UITableView strange behaviour when using more than 1 Prototype Cell

So I have a UITableView which I plan to use 2 prototype cells inside of it. Let's call them Cell A and Cell B. Cell A has it's own layout and Cell B has it's own layout.
Here's the thing, in a typical UITableView implementation with only 1 prototype cell, after setting up all the cell and it's properties, cellForRowAtIndexPath takes care of populating all the rows based on the (x) number of items from numberOfRowsInSection.
Here is where I am having a problem. I've implemented both my prototype cells in my UITableView and when I run it, I notice cellForRowAtIndexPath is only being called twice, even though I have a value in (x) number of items which is greater than 2. Doesn't matter what I set it to, it only gets called twice. I already have the necessary if statements to pick a cell prototype based on the cell index etc...so that's not the issue. The issue is cellForRowAtIndexPath just gets called twice instead of looping thru all the items.
Why is this and how can I fix it?
This is my code for the DataSource methods:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 8
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
Scripts.log("Data Count = \(indexPath.row)")
if indexPath.row == 0{
var cell: ContactDetailImageCell = tableView.dequeueReusableCellWithIdentifier(NAME_OF_CUSTOM_IMAGE_CELL) as ContactDetailImageCell
cell.cardPhoto.image = aContact.profilePicture
cell.fullName.text = aContact.getDisplayName()
cell.workplace.text = aContact.workplace
return cell
}
else{
var cell: ContactDetailPhoneNumCell = tableView.dequeueReusableCellWithIdentifier(NAME_OF_CUSTOM_PHONE_CELL) as ContactDetailPhoneNumCell
return cell
}
return UITableViewCell()
}
What height are your cells? cellForRowAtIndexPath will only get called if the table thinks it needs to display the cell. Hence the whole reuse mechanism. So if you have 8 cells and it thinks 2 fill the screen it will not ask for any more until you scroll up/down.
What are you returning for heightForRowAtIndexPath.

Swift UITableView didSelectRowAtIndexPath bug

I have a UITableView with the subtitles hidden but set up where when someone selects a cell it shows that cell's subtitle. This works fine except that after tapping any cell to reveal its subtitle if you scroll down you will find that every 12 cells have their subtitle unhidden (as well as the one it was supposed to reveal). Here is the code I'm using in didSelectRowAtIndexPath:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
for cell in tableView.visibleCells() {
cell.detailTextLabel??.hidden = true
}
var cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.detailTextLabel?.hidden = false
}
I'm sure this is related to ".visibleCells()" since every 12 cells is about the height of my visible table on my iPhone 6 Plus. When I run it on a 4s in the simulator it's about every 8 cells. But I'm not sure how else to do it besides 'visibleCells'? But it's strange because it's the whole table - all the way down, every 12 cells is showing its subtitle...
thanks for any help
UITableView reuses its cells. So the cell for row a row you clicked on (unhidden the subtitle) may be used for row another row.
The solution is to define prepareForReuse() method in the UITableViewCell subclass (or make the subclass if you do not have one) and hide the subtitle again there.
Add that dataSource's method to your controller. Should work fine.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
var identifier = "cellIdentifier"
var cell = tableView. dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath)
cell.detailTextLabel?.hidden = true
return cell
}

Resources