Custom header of table view with IB - ios

I would like to create a custom header for a table view section with interface builder. I cannot use the method titleForHeaderInSection because i need to display two labels. I used this instructions: Customizing Header and Footer of TableView in iOS8 but it does not work.
What I have done so far:
Create a custom class CustomTableCell which inherits from UITableViewCell
class CustomTableCell: UITableViewCell {
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var dateDescriptionLabel: UILabel!
}
Create a dynamic prototype cell in storyboard
Add an identifier
Connect the labels to the custom UITableViewCell
Implement viewForHeaderInSection
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("CustomTableCell") as CustomTableCell
headerCell.backgroundColor = UIColor.cyanColor()
headerCell.dateLabel.text = "Test date"
headerCell.dateDescriptionLabel.text = "Test date description"
return headerCell
}
When i run the app the section appears one second and then moves under the table cells and I get an error: no index path for table cell being reused.
What is wrong with this solution? I downloaded the project from the tutorial I have linked and it works there.

Your problem has its roots in how UIKit handles UITableViews.
To make sure table views are fast and responsive, even with a large amount of cells, the cells are re-used.
By calling tableView.dequeueReusableCellWithIdentifier("CustomTableCell") you are asking the tableView to give you a cell to reuse.
A lot of people have been using the reusable cells to design their headers/footers in Storyboards. Ever since iOS 7 Beta 5 this may lead to errors. This answer explains the situation well: What is the meaning of the “no index path for table cell being reused” message in iOS 6/7?
To design your own custom header/footer views I don't recommend using UITableViewCells. Instead you should create and design a custom UIView directly in your code. If you want to use Interface Builder you could create a .xib or create a view in your Storyboard that is not a subview of the actual controller's view.

Related

'Outlets cannot be connected to repeating content' in subclass of UICollectionViewCell

Xcode 9.2, Swift 4. For a cell in a Collection View Controller, I created a subclass named CollectionViewController. I linked the cell to this subclass. I created a Label in the cell on the Main.storyboard and linked it to the subclass like this :
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var personName: UILabel!
}
Then i try to access to this label in the collectionView function inside my CollectionViewController class, subclass of UICollectionViewController, which is linked to the Collection View Controller where my cell is :
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
cell.personName.text = "text"
return cell
}
That's how i have this error : "The personName outlet from the UICollectionView to the UILabel is invalid. Outlets cannot be connected to repeating content."
I'd suggest you double check the "connections inspector" (the last tab on the panel on the right) for that control (and any other controls inside that cell). It sounds like something in the cell has a lingering outlet hooked up to the view controller. The connections inspector will help you identify that:
Make sure the view controller doesn't show up as one of the outlets. In the above example, I have "accidentally" created two outlets for this label, one to the cell subclass (which is correct) and one to the view controller (which is incorrect).
That will result in a compile-time error that says:
error: The customLabel outlet from the ViewController to the UILabel is invalid. Outlets cannot be connected to repeating content.
If you delete the outlet connection between the cell and the view controller (or whatever non-cell class it's hooked up to), and this compile-time error will go away.
Note, the sentence before the "Outlets cannot be connected to repeating content" message will tell you precisely which outlet is causing the problem. You can even click on this error inside the "issues navigator" in the left panel and Xcode will jump to the storyboard and select the offending control (at which point you can directly open up the connections inspector) and find the offending outlet.
Additional note for similar error condition:
In the error message I got, along with the message similar to above, Xcode(ver 12.0) also provided the Object ID, which I referred to in the Identity Inspector tab to eradicate the cause of the error.
solution: From viewcontroller
kindly remove the IBoutlet of colllectionviewcell
. the issue mentions the invalid of your IBOutlet. so remove all subclass which has multi-outlet(invalids) and reconnect it.
The answer is already mentioned in another question

Can I use a single custom cell for multiple different cells?

I have created a single prototype cell which has two labels (mainLabel and subLabel) and an uiimageview. In the uitableview I'd like to have several cells which reuse the prototype and when needed the subLabel is hidden and the uiimageview is changed with different one or with a uiswitch. The two labels have different text for each cell. Do you have any suggestions/hints in order to do it? possibly in a mvvm architecture?
I'll describe what I am doing:
I have a struct (the Model) with two properties: label and sublabel. This is then instantiate by a viewModel which provides text for each cell, done by a method called getModel(_ indexPath: IndexPath) -> cellModel { ... }. Finally in UIViewController, in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) { ... } I am calling getModel(), using dequeueReusableCell and setting up each cell.
In getModel() there is a huuuuge switch which I use to know which cell is which
Then in uitableviewcell I have some method that hides sublabel and changes uiimageview.
It kind of works, however I have some issues with while scrolling. For example, sometimes a uiimageview is drawn in another cell, or a subLabel is hidden, even if it is not supposed to. I guess this is due because it is reusing the cell, and I am not resetting it.
Anyway, any suggestions or ideas?
I know this is overkilling...
No need for any pattern. Yes, you can use that single cell design for all cells. Just hide/empty label(s) and image view as you like per cell.
First of all you have to set default value to both the labels and imageview
i.e. (consider a title label, a sub label and a imageview)
lblTitle.isHidden = false
lblSubLabel.isHidden = false
imgViewIcon.image = nil
Then just show labels in specific condition that you want to match and set image in imageview
i.e. (consider your condition to hide sub label)
if needToHide == true {
lblSubLabel.isHidden = true
}

Xcode (Swift) error - use of undeclared type 'CustomCell'

I've been learning table views from tutorials on YouTube. I was following every step told in the video, and did everything the same as the author of this tutorial, but for some reason I got a strange error - I've heard that it's about old version of Xcode used in the tutorial - I'm working on the latest one.
Debugger tells that "CustomCell" is undeclared.
Every help will be appreciated!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfCwiczenia.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: CustomCell = tableView.dequeueReusableCellWithIdentifier("Cell") as CustomCell
let person = arrayOfCwiczenia[indexPath.row]
cell.setCell(cwiczenia.nazwa, imageName: cwiczenia.obrazek)
return cell
}
CustomCell looks to be a subclass of UITableViewCell
Looks like they left out the part where you need to create it
Create a new file called CustomCell and make sure it's base class is UITableViewCell
You must have a file where you define the behaviour of the custom cell - if that's not called 'CustomCell' then it won't be declared.
Just make sure that you have the same name when you define the class and when you use it.
I would suggest looking at Apple's walkthrough on how to implement a table view. It has step by step instructions with pictures. If you scroll down the the Design Custom Table Cells section I think you will be able to see how to link the custom cell to a file properly
Your tutorial should have mentioned all the details, but here it goes...
You need to define a subclass of UITableViewCell named CustomCell:
import UIKit
class CustomCell: UITableViewCell
{
// Your custom properties/methods.outlets/etc.
}
(typically, in a source file named CustomCell.swift, but this is not compulsory)
If you are using a storyboard, you need to set the class of your prototype cells to "CustomCell" in the identity inspector (third tab from the left on the right inspector pane - the one with the icon that looks like a newspapaer):
Also, In the attributes inspector (fourth tab from the right, icon looks like a slider), set the cell's identifier (in the case of your code, "Cell"):
If you are not using a storyboard, you need instead to register the custom cell class and identifier programmatically:
func viewDidLoad()
{
tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "Cell")
// other setup...
}
I had this same error. Tried cleaning and building which worked but the main issue seemed to just be saving the CustomCell which then becomes recognised by the compiler and removes the error.
Its not limited to cells I've had it with other custom classes before as well. Good one to know about though!

Swift Custom Cell creating your own Cell with labels

I've just started to use Swift as a prorgamming language and i've run into a problem with Custom cells.
When i try to create custom cells, and then go forward and try to design them the way i need them ( with Style set to Custom ) everything looks good. Now i don't know how to put specific data into them, since all tutorials i found used the style option "basic" where they only have a text label to which they assign their data.
Now for me, when i "control drag" my labels into my code, i give them specific names such as "dateLabel" or "sourceLabel" in order to insert the data correctly.
now i'm not sure, and couldn't find any answers that worked, on how to recall my custom made labels so that i can assign my data to them...
Maybe someone of you could help me with this, since i'm pretty sure it's a simple problem but i coudln't find any resources to this ^^
hopefully the font isn't to small, i just wanted you guys to see the erros i get.
I used the following tutorial as a guide line, since it was the only one that worked just the way this guy did it: https://www.youtube.com/watch?v=0qE8olxB3Kk
I checked the identifier and he is set correctly and i can't find anything online on how i have to properly refer to my own labels with their correct names.
any help would be appreciated :)
Try the following steps:
Create a custom table view cell class that extends UITableViewCell. In my example, the custom table view cell class is called MyCustomTableViewCell.
Update your storyboard's cell so that it uses your custom table view cell class. Go to the Identity Inspector and set the Class value to the name of your custom table view cell class.
Update your storyboard's cell and give it a reuse identity value. Go to the Attributes Inspector and set the Identifier value. For example, I gave my cell an Identifier value of MyCustomCell.
Control drag the cell's labels into your new custom table view cell class (i.e., the MyCustomTableViewCell class).
Once you have done the above steps, you will be able to access the labels when you dequeue your cell in the tableView:cellForRowAtIndexPath: method. As the code snippet below shows, you will need to: 1) get the cell using the reuse identifier you established in the steps above and 2) cast to your custom table view cell class.
For example, here's what your custom table view cell would look like if you named it MyCustomTableViewCell. This is after you created the class and control dragged your labels into this class.
class MyCustomTableViewCell: UITableViewCell {
#IBOutlet weak var categoryLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var sourceLabel: UILabel!
#IBOutlet weak var titleLabel: UILabel!
}
Your ViewController could look like this:
// NOTE: I subclassed UITableViewController since it provides the
// delegate and data source protocols. Consider doing this.
class ViewController: UITableViewController {
// You do NOT need your UILabels since they moved to your
// custom cell class.
// ...
// Omitting your other methods in this code snippet for brevity.
// ...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Use your cell's reuse identifier and cast the result
// to your custom table cell class.
let article = tableView.dequeueReusableCellWithIdentifier("MyCustomCell", forIndexPath: indexPath) as! MyCustomTableViewCell
// You should have access to your labels; assign the values.
article.categoryLabel?.text = "something"
article.dateLabel?.text = "something"
article.sourceLabel?.text = "something"
article.titleLabel?.text = "something"
return article
}
}

Swift MVC Design With Multiple Table Views

So I have the main view of my controller that has a table view. This table view will be displaying many different custom classes that subclass UITableViewCell. Some of these cells will ALSO have table views inside of them.
My problem is that I do not know what class I should assign to to be the UITableViewDelegate in this sort of situation for the table view in the table view cell. My intial thought was to make it the cell view class:
class MyTableViewCell: TableViewCell {
#IBOutlet var tableView: UITableView!;
var messages: Array<String>?;
//called by parent tableview when cellForRowAtIndexPath is called in main controller
//to initialize view with dynamic properties at run time
override func render(obj: MyObject) {
messages = obj.getMessages();
}
}
extension MyTableViewCell: UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages == nil ? 0 : messages!.count;
}
}
This is problematic because I have no where to register my nib files to the table view:
nib = UINib(nibName: "MyTableViewCell", bundle: nil);
self.tableView.registerNib(nib!, forCellReuseIdentifier: "custom");
Also, I feel like making a view a table view data source is violating MVC principles. What is the best way to go about with my table views within table view cells?
The UITableView within a UITableCell was indeed implemented in Pulse as described by genalipsis. In Obj-C,there is a full tutorial plus posted code located here for UITableView within a UITableCell:
http://iosstuff.wordpress.com/2011/06/29/adding-a-uitableview-inside-a-uitableviewcell/
http://iosstuff.wordpress.com/2011/06/29/creating-pulse-style-scrolling-horizontally-scrolling-uitableview-as-a-subview-of-uitableviewcell/
The was done in Xcode 4. I am not sure if this will work in Xcode 6.1 but it does describe a methodology.
I think an even more descriptive and easier to follow tutorial was posted at Ray Wenderlich's site here:
http://www.raywenderlich.com/4680/how-to-make-an-interface-with-horizontal-tables-like-the-pulse-news-app-part-1
http://www.raywenderlich.com/4723/how-to-make-an-interface-with-horizontal-tables-like-the-pulse-news-app-part-2
Create a regular UITableView
Create a custom UITableViewCell
Add a rotated UITableView as a subview of our UITableViewCell
Create another custom UITableViewCell for our articles
Rotate our custom cell and use it for our horizontal table view
While the tuorial was from 2011, some of the comments are very recent, so the approach must still work.
There is also a github project that references a stack overflow discussion from earlier this year:
https://github.com/hefgi/TableViewInTableViewCell
If you open the project, the storyboard file for the iPhone is instructive (Main_iPhone.storyboard):
A table view inside of a table view has been done before. One of the first iPad Apps, Pulse, used this strategy to allow uses to scroll vertically between RSS feeds and horizontally, within each cell, between RSS entries. That is, the embedded table view was rotated and the cells inside it where also rotated so that their orientation allowed reading.
For usability reasons, you will probably want to follow a similar pattern, else it might be difficult to scroll.
Tentative architecture: MainTableViewController is the controller for the table view that contains sub table views. SubTableViewController is the controller for the table views contained within the cells of the MainTableViewController. This approach lets you use TableViewControllers in the "standard" fashion
class MainTableViewController: TableViewController {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//dequeue a cell or create an instance of a cell
//create instances of SubTableViewController or change the data source for indexPath
//add the view of SubTableViewController to the cell's view hierarchy
//make necessary view adjustments depending on orientation, etc.
}
Not a standard setup, so I would expect that a few further hacks will be necessary.

Resources