I have an issue with UITableView inserted in a UITableViewCell. This is my custom cell:
Everything works fine for the first, second and third cells, but from the fourth cell for the content of the UITableView inserted in cell is used always the same rows of the first, second and third cells alternatively. Instead the labels outside the UITableView are correctly displayed in every cells. This is my code for the custom cell class:
import UIKit
class SimulazioneQuestionTableViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
let cellIdentifier = "simRisposteCell"
var arrayRisposte = [Risposta]()
#IBOutlet var numeroLabel: UILabel!
#IBOutlet var domandaLabel: UILabel!
#IBOutlet var risposteTableView: UITableView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
var nib = UINib(nibName: "SimulazioneQuestionAnswerTableViewCell", bundle: nil)
self.risposteTableView.registerNib(nib, forCellReuseIdentifier: self.cellIdentifier)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayRisposte.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as SimulazioneQuestionAnswerTableViewCell
cell.textLabel?.text = arrayRisposte[indexPath.row].testo
return cell
}
}
And this is my view controller:
import UIKit
class SimulazioneViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var areaSimulazione: Int = Int()
var arrayDomande = [Domanda]()
var arrayRisposte = [[Risposta]]()
var cellIdentifier = "domandaSimulazioneCell"
#IBOutlet var tempoTrascorso: UILabel!
#IBOutlet var simulazioneTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
arrayDomande = ModelManager.instance.getSimulazione(area: areaSimulazione)
var nib = UINib(nibName: "SimulazioneQuestionTableViewCell", bundle: nil)
self.simulazioneTableView.registerNib(nib, forCellReuseIdentifier: self.cellIdentifier)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayDomande.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: SimulazioneQuestionTableViewCell = simulazioneTableView.dequeueReusableCellWithIdentifier(self.cellIdentifier) as SimulazioneQuestionTableViewCell
var domanda: Domanda = arrayDomande[indexPath.row]
var rispXDomanda = ModelManager.instance.getAnswersForQuestion(domanda.numero)
cell.numeroLabel.text = String(domanda.numero)
cell.domandaLabel.text = domanda.testo
cell.arrayRisposte = rispXDomanda
return cell
}
Some advice to resolve this issue?
Thank you guys!
I never had the idea of putting a UITableView inside a UITableViewCell and therefore would have approached this from a different direction. I'm not saying the table inside a cell is impossible or a bad idea, but the following approach might actually be easier.
My understanding is that your table view shows a number of questions, and each question has possible answer right below it.
I'd use one section per question, with the first row using a custom cell that shows the numeroLabel and the domandaLabel (basically SimulazioneQuestionTableViewCell without the table), and then put the answers into the remaining rows for the section.
private let QuestionCellIdentifier = "QuestionCell"
private let AnswerCellIdentifier = "AnswerCell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return arrayDomande.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let rispXDomanda = ModelManager.instance.getAnswersForQuestion(domanda.numero)
return 1 + rispXDomanda.count // one extra for the question
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let domanda = arrayDomande[indexPath.section]
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier(QuestionCellIdentifier) as SimulazioneQuestionTableViewCell
cell.numeroLabel.text = String(domanda.numero)
cell.domandaLabel.text = domanda.testo
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier(AnswerCellIdentifier) as SimulazioneQuestionAnswerTableViewCell
let rispXDomanda = ModelManager.instance.getAnswersForQuestion(domanda.numero)
cell.textLabel?.text = rispXDomanda[indexPath.row - 1].testo
return cell
}
It might be a good idea to cache the answers that you get from ModelManager. It depends on how expensive it is to get them - with the code above getAnswersForQuestion() will be called a lot.
Edit: I personally like the .Grouped style for the table view. Using a section per question will nicely separate them visually.
Related
No data is appearing in my Swift table. I'm fairly new to Swift and not quite sure why this or what I might be missing. I followed the guide here for the most part with some differences:
Apple Table Creation
Here's the tableView definition:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "AccountTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? AccountTableViewCell else {
fatalError("The dequeued cell is not an instance of AccountTableViewCell.")
}
let item = userDataSource[indexPath.row]
// Dummy values just to test this out
cell.leftLabel.text = "test1";
cell.rightLabel.text = "test2";
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1;
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) ->Int {
return userDataSource.count;
// This should be an array value, but I have also tried passing a static int here as well to test
}
Here is my class definition with the implemented procotols:
class AccountViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
And here is my table cell definition:
class AccountTableViewCell: UITableViewCell {
//MARK: Properties
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: 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
}
}
I've got both rightLabel and leftLabel setup in the Storyboard.
I can go to the account page represented by this view controller and a table display does come up - it just has absolutely no data in it.
What am I missing?
It is not sufficient to simply add a UITableView to your view controller scene. You must set the tableview's dataSource property to your view controller instance in the Storyboard connections inspector for the tableview.
I created a UITableView in a UIViewController from the storyboard and create custom tableViewCell class. Now when I run my project,
It is not scrolling when I touch any cell and move up/down.
BUT, it scrolls if I start scrolling with the either end of UItableViewCell (nearly, 15px of left inset).
I tried to create another fresh tableView, still not working.
I tried to create a tableViewController, still not working.
Then I think the code is NOT the cause of the issue.
Using Xcode 8.2.1
Below is my code work :
Class File
struct Quote {
var text: String
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView?
let cellIdentifier = "cell"
// Array of strings for the tableView
var tableData = [Quote(text: "zadz ad azd azds fsd gdsfsd"), Quote(text: "zakd gqsl jdwld bslf bs ldgis uqh dm sd gsql id hsqdl sgqhmd osq bd zao mos qd"), Quote(text: "azdhsqdl sb ljd ghdlsq h ij dgsqlim dhsqihdùa dbz ai ljsm oqjdvl isq dbvksqjld"), Quote(text: "dsqb jhd gs qdgsq dgsq u hdgs qli hd gsql i dgsq li dhs qij dhlqs dqsdsd.")]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: self.cellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return number of rows in table
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Create Resusable Cell, get row string from tableData
let cell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier)! as! cellClass
let row = indexPath.row
// Set the labels in the custom cell
cell.mainText.text = tableData[row].text
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Do what you want here
let selectValue = self.tableData[indexPath.row]
print("You selected row \(indexPath.row) and the string is \(selectValue)")
}
}
And this is my cellClass: (Custom cell)
class cellClass: UITableViewCell {
#IBOutlet weak var mainText: 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
}
}
Storyboard hierarchy of UITableView
You might be have some x-code issues because generally it never happens and I run your project it working properly as usually it works.
Below is code work I have done.
I'm not taking sturcture of array like you, I'm just doing with taking simple array.
my array is
arrayData = ["One", "Two", "three", "four"]
below is cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : cellClass = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! cellClass
cell.lblstates.text = arrayData[indexPath.row]
return cell
}
If you facing any issue then let me know.
Check if the user interaction Enabled check of your cell is off or not in the storyboard
Resolved: I had to uninstall and install Xcode again..
So I am currently trying to populate a tableview with custom cells based on an API call. After I get the data to populate with, I reload the tableview. It has the data based on how many cells it has, but each one is blank. I've looked over some similar problems people had, but can't seem to find the fix. Any help would be great, thank you!
I call my API and collect the data I need. Then I reload the tableview.
class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
#IBOutlet var typeSwitch: UISegmentedControl!
#IBOutlet var searchBar: UITextField!
var timeoutTracker = 0
var items: [String] = []
var count = 1
func searchCall() {
Alamofire.request("http://www.plex.dev/api/search/" + type + "/" + searchBar.text!).responseJSON { response in
debugPrint(response)
if response.response == nil {
self.timeoutTracker = self.timeoutTracker + 1
if self.timeoutTracker == 5 {
self.timeoutTracker = 0
self.popUp()
}
else {
sleep(2)
self.searchCall()
}
}
if let json = response.result.value {
let jsonTest = JSON(json)
for x in jsonTest["results"] {
if let title = x.1["title"].string {
self.items.append(title)
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.reloadData()
}
}
}
}
}
func tableView(_ tableView:UITableView, numberOfRowsInSection section:Int) -> Int
{
return self.items.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = self.tableView.dequeueReusableCell(withIdentifier: "cell")! as! MovieCell
cell.movieTitle?.text = self.items[indexPath.row]
cell.moviePoster?.image = #imageLiteral(resourceName: "avatar.png")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
Here is the custom Cell Class
import UIKit
class MovieCell: UITableViewCell {
#IBOutlet var moviePoster: UIImageView!
#IBOutlet var movieTitle: UILabel!
#IBAction func addMovie(_ sender: AnyObject) {
}
}
Here is my storyboard:
And here is my blank tableview:
I hope it isn't something obvious, but thanks for the help either way!
EDIT: changing my identifier to something other than "cell" seemed to do the trick
Are you calling the searchCall() anywhere?
Also would suggest you to declare
tableView.delegate = self
tableView.dataSource = self
in viewDidLoad() of the SearchViewController and add the delegates and datasource of the UITableView as an extension to SearchViewController (it is a better code practice)
EDIT: After looking again at your cellForRowAt: try and replace your code with the following
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MovieCell
and not use self.tableView here
EDIT 2: Sometimes using the default cell identifier 'cell' can cause some problems, so better to use a different one such as 'movieCell'
I suspect you are registering a class or nib with your table view, but when you use prototype cells you should not do this. Also, you should use the more modern dequeueReusableCell(withIdentifier: String , for indexPath: IndexPath). Also, I would resist the temptation to ever call sleep.
Did you give the class to the cell and connect the outlets in cell
I have the following class for a table view cell:
class QuestionCell: UITableViewCell {
#IBOutlet weak var questionAnswer: UISwitch!
#IBOutlet weak var questionLabel: UILabel!
var data: Answer?
func configureForQuestion(data: Answer) {
print("configureForQuestion triggered")
questionLabel.text = data.question
self.data = data
}
#IBAction func questionAnswerChanged(sender: UISwitch) {
data?.answer = sender.on
}
}
This cell consists of a label and switch. Currently when I change the switch status for the first row, it is also changing for the last row. No other rows seem to be connected in this way. I'm pretty stumped on this one.
Extra info:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return answers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(TableView.CellIdentifiers.QuestionCell, forIndexPath: indexPath) as! QuestionCell
cell.configureForQuestion(answers[indexPath.row])
return cell
}
You need to override prepareForReuse in the cell and reset you ui elements data.
override func prepareForReuse() {
self.questionLabel.text = nil
self.questionAnswer.on = data?.answer
}
It may be that your answers array does not have the data you expect. Print out the values of answers in the debugger and see if each answer has the indexPath.row you expect it to have.
Can you show your code for how you set the values in answers?
I'm trying to make a view controller that has one text field that populates the tableview below, ideally the user will be able to continue to add to the tableview without jumping between two views.
I previously had it working with the text field on one view that populates a UITableView and used prepareForSegue to push the data to the table, but I haven't been able to get it to work with just one view.
Can anyone please point out where I'm going wrong or push me to a tutorial / documentation to help?
Edit: Clarity
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var tableView: UITableView!
#IBOutlet weak var textField: UITextField!
var items: [String] = ["Pls", "work", "pls", "work", "pls"]
var foodGroup: FoodGroup = FoodGroup(itemName:"")
//var foodGroup: [FoodGroup] = []
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel.text = self.items[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("Selected cell #\(indexPath)")
}
func addFood(sender: AnyObject!) {
if (countElements(self.textField.text) > 0) {
self.foodGroup = FoodGroup(itemName: self.textField.text)
}
}
#IBAction func addFoodToList() {
let source = FoodGroup
let foodGroup:FoodGroup = source.foodGroup
if foodGroup.itemName != "" {
self.foodGroup.append(foodGroup)
self.tableView.reloadData()
}
}
}
It seems like your intention here is to have your dataSource be an array of FoodGroup objects. If this is indeed the case you can get rid of your foodGroup instance variable and update your items definition to be like so:
var items = [FoodGroup]()
then in addFoodToList:
if self.textField.text != "" {
let foodGroup = FoodGroup(itemName: self.textField.text)
self.items.append(foodGroup)
self.tableView.reloadData()
}
and finally in cellForRowAtIndexPath:
var cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
let foodGroup = self.items[indexPath.row] as FoodGroup
cell.textLabel.text = foodGroup.itemName
return cell
Also I don't quite see the intention of your the addFood(sender: AnyObject!) function. Looks like cruft. I would get rid of it. Good luck!