Custom Cells Returning Blank in TableView Swift 3 - ios

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

Related

How to initialize UI things when reuse a UITableViewCell

I want to reuse a UITableViewCell in my app, but I get this error: Unexpectedly found nil while implicitly unwrapping an Optional value.
I find that this is because the UI things in UITableViewCell is nil, so my app crashed.
My UITableViewCell code is like this:
class WordListCell: UITableViewCell {
#IBOutlet weak var wordListCoverImage: UIImageView!
#IBOutlet weak var wordListName: UILabel!
#IBOutlet weak var wordListInfo: UILabel!
var wordList: WordList? {
didSet {
updateUI()
}
}
private func updateUI() {
wordListName.text = wordList?.name
wordListInfo.text = wordList?.description
wordListCoverImage = UIImage()
}
}
I create it in the storyboard and link the outlet to the code in the other TableView.
But this time, I want to reuse the cell in a new TableView which is all created by code, so I don't know how to initialize the UI things.
The new UITableView code is like this:
tableView.delegate = self
tableView.dataSource = self
tableView.register(WordListCell.self, forCellReuseIdentifier: "wordListCell")
//the delegate
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return wordLists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let wordList = wordLists[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "wordListCell", for: indexPath)
if let wordListCell = cell as? WordListCell {
wordListCell.wordList = wordList
}
return cell
}
Please tell me how to reuse the cell.Thanks!
Okay so I think what you are doing wrong is when you create a custom tableView cell, you are not assigning a UIImage. So instead try doing this wordListCoverImage = UIImage(named: wordList.imageName).
Now also in your tableView class inside viewDidLoad() apart from adding
tableView.delegate = self
tableView.dataSource = self
tableView.register(WordListCell.self, forCellReuseIdentifier: "wordListCell")
Then at let cell = tableView.dequeueReusableCell(withIdentifier: "wordListCell", for: indexPath) downcast it as a custom cell class like so.
let cell = tableView.dequeueReusableCell(withIdentifier: "wordListCell", for: indexPath) as! WordListCell
And then finaly under that set the cell.delegate = self
I hope this helps!

I have set value for cell of UITableView but why it didn't display?

I have created a UITableView and a UITableVIewCell in Main.storyboard and set it's dataSource and delegate to ViewController .Why UITableView didn't display texts when I run the code.
Another question is that does UITableView load before ViewLoad? If not why in func didRecieveResults() the Array of tableData can achieve datas but in func tableView() it was nil
The whole codes as following
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,HttpProtocol {
#IBOutlet weak var tv: UITableView!
#IBOutlet weak var iv: UIImageView!
#IBOutlet weak var playTime: UILabel!
#IBOutlet weak var progressView: UIProgressView!
var eHttp:HttpController = HttpController()
var tableData:NSArray = NSArray()
var channelData:NSArray = NSArray()
override func viewDidLoad() {
super.viewDidLoad()
eHttp.delegate = self
eHttp.onSearch("http://www.douban.com/j/app/radio/channels")
eHttp.onSearch("http://douban.fm/j/mine/playlist?channel=0")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
println("tableData.count:\(channelData)")
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell!{
let cell = UITableViewCell(style:UITableViewCellStyle.Subtitle,reuseIdentifier:"douban")
let rowData:NSDictionary = self.tableData[indexPath.row] as! NSDictionary
cell.textLabel!.text = "hehehehe"//rowData["title"] as! String
cell.detailTextLabel!.text = "adasdasda"//rowData["artist"] as! String
return cell
}
func didRecieveResults(results:NSDictionary){
if (results["song"] != nil){
self.tableData = results["song"] as! NSArray
println(tableData)
}else if (results["channels"] != nil){
self.channelData = results["channels"] as! NSArray
// println(channelData)
}
}
}
As Lukas points out, you need to return the UITableViewCell at the end of the method.
In fact, what you posted shouldn't even compile, so I'm wondering if you posted your sample code incorrectly.
The first thing to try, and actually return the cell, update your code to:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell!
{
let cell = UITableViewCell(style:UITableViewCellStyle.Subtitle,reuseIdentifier:"douban")
let rowData:NSDictionary = self.tableData[indexPath.row] as! NSDictionary
cell.textLabel!.text = "hehehehe"//rowData["title"] as! String
cell.detailTextLabel!.text = "adasdasda"//rowData["artist"] as! String
// YOU ARE MISSING THIS LINE
return cell
}
Also ensure that you UITableViewDatasource is set properly, and that the required methods are functioning. Specifically, both numberOfRowsInSection and numberOfSectionsInTableView need to be returning values greater than 0. (In the code you posted, you are missing numberOfSectionsInTableView)
As Lukas said in a comment, you should make sure you return a value from your cellForRowAtIndexPath method otherwise it will refuse to build. If you've done that and you still don't see any cells, it's probably because either numberOfRowsInSection or numberOfSectionsInTableView are returning 0, so you should make sure they return a positive integer.

Swift - UITableView inside UIViewController, UITableView functions are not called

I inserted a tableview inside a UIViewController. But my code is not working. When I checked I found that none of the tableview functions are not called.
class CustomViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var authorArticlesTableView: UITableView!
var authorid: Int!
var authorname: String!
var articles: [JSON]? = []
func loadArticles(){
let url = "http:here.com/" + String(authorid) + "/"
println(url)
Alamofire.request(.GET, url).responseJSON { (Request, response, json, error) -> Void in
if (json != nil){
var jsonObj = JSON(json!)
if let data = jsonObj["articles"].arrayValue as [JSON]?{
self.articles = data
self.authorArticlesTableView.reloadData()
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.loadArticles()
println("viewDidLoad")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println("numberOfRowsInSection")
return self.articles?.count ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell
cell.articles = self.articles?[indexPath.row]
println("cellForRowAtIndexPath")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("WebSegue", sender: indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
Any solution for this?
Thanks,
You have to set your view controller as a table view delegate/datasource:
add to the end of the viewDidLoad:
authorArticlesTableView.delegate = self
authorArticlesTableView.dataSource = self
Set table delegate and dataSource :
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
Sometimes, if you forget to drap and drop UITableViewCell to UITableView. XCode don't understand TableView has Cell.
By default, when you drap and drop UITableView into UIViewController. I see UITableView has Cell. But you need to drap and drop UITableViewCell into UITableView also.
It is work with me.
Makes sense to do it in your
#IBOutlet weak var authorArticlesTableView: UITableView!
so it will become
#IBOutlet weak var authorArticlesTableView: UITableView! {
didSet {
authorArticlesTableView.delegate = self;
authorArticlesTableView.dataSource = self;
}
}

Display the same content in UITableView included in custom UITableViewCell

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.

UITextField and UITableView on a single view controller

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!

Resources